home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 January / enter-2004-01.iso / files / maxima-5.9.0.exe / {app} / share / maxima / 5.9.0 / src / nparse.lisp < prev    next >
Encoding:
Text File  |  2003-02-09  |  58.3 KB  |  1,905 lines

  1. ;;; -*-  Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
  2. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3. ;;;     The data in this file contains enhancments.                    ;;;;;
  4. ;;;                                                                    ;;;;;
  5. ;;;  Copyright (c) 1984,1987 by William Schelter,University of Texas   ;;;;;
  6. ;;;     All rights reserved                                            ;;;;;
  7. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  8. ;;;     (c) Copyright 1981 Massachusetts Institute of Technology         ;;;
  9. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  10.  
  11. (in-package "MAXIMA")
  12.  
  13. (macsyma-module nparse)
  14. (load-macsyma-macros defcal mopers)
  15.  
  16. (proclaim '(optimize (safety 2) (speed 2) (space 2)))
  17. (DEFMVAR ALPHABET
  18.   '(#\_ #\%)
  19.   "alphabetic exceptions list")
  20. ;;;  Note: The following algorithms work only in environments where 
  21. ;;;        ascii codes for A,...,Z and 0,...,9 follow sequentially.
  22. ;;;       Normal ASCII and LispM encoding makes this true. If we ever
  23. ;;;       bring this up on EBCDIC machines, we may lose.
  24.  
  25. (DEFMACRO IMEMBER (X L)
  26.   #+(OR CL NIL) `(MEMBER ,X ,L)
  27.   #-(OR CL NIL) `(zl-MEMBER ,X ,L))
  28.  
  29. #-cl ;;defined in commac or via common
  30. (cond ((not (fboundp 'char<=)))
  31.  (defun char<= (a b) (<= a b))
  32.  (defun char>= (a b) (>= a b)))
  33.  
  34.  
  35. (PROGN
  36.  
  37. (DEFMVAR ALPHABET '(#\_ #\%))
  38.  
  39. (DEFMFUN ALPHABETP (N)
  40.  #-cl (DECLARE (FIXNUM N))
  41.  (and (characterp n)
  42.  (OR (AND (CHAR>= N #\A) (CHAR<= N #\Z))  ; upper case
  43.      (AND (CHAR>= N #\a) (CHAR<= N #\z)) ; lower case
  44.      (imember n '(#\_ #\%))
  45.      (IMEMBER N ALPHABET))))
  46. ; test for %, _, or other declared
  47.                   ;    alphabetic characters.
  48. (DEFMFUN ASCII-NUMBERP (NUM)
  49.   #-cl (DECLARE (FIXNUM NUM))
  50.   (AND (characterp num) (CHAR<= NUM #\9) (CHAR>= NUM #\0)))
  51.  
  52. (DEFUN GETALIAS (X) (COND ((GET X 'ALIAS)) ((EQ X '$FALSE) NIL) (T X)))
  53.  
  54. )
  55.  
  56.  ;End of #-LISPM
  57.  
  58. ;dbg:  ;;signals a conditition 'dbg:parse-ferror
  59. ;(DEFUN PARSE-FERROR (format-ctl-STRING &REST FORMAT-ARGS)
  60. ;  (ERROR 'PARSE-FERROR ':format-string FORMAT-ctl-STRING ':FORMAT-ARGS (COPY-LIST FORMAT-ARGS)))
  61.  
  62. (defvar *parse-window* nil)
  63.  
  64. (DEFUN MREAD-SYNERR (sSTRING &REST L)
  65. ;  #+lispm (sys:parse-ferror    (format nil sstring l)  :correct-input )
  66.   #+lispm (dbg:parse-ferror    (format nil sstring l)  :correct-input )
  67.   #+(OR  NIL) (APPLY #'ERROR #+LISPM NIL #+NIL ':READ-ERROR sSTRING L)
  68.   #-(OR LISPM NIL)
  69.   (progn 
  70.     (let (tem 
  71.       errset
  72.       (file "stdin"))
  73.       (errset
  74.        (setq tem (file-position *parse-stream*))
  75.        (setq file  (namestring *parse-stream*)))
  76.       (cond (tem (format t "~%~a:~a:"  file  tem))
  77.         (t ;(terpri)
  78.            ))
  79.       (format t "Incorrect syntax: ")
  80.       (apply 'format t sstring l)
  81.       (cond ((output-stream-p *standard-input*)
  82.          (let ((n (get '*parse-window* 'length))
  83.            some ch
  84.            k
  85.            )
  86.            (sloop for   i below 20
  87.               while (setq ch (nth (- n i 1) *parse-window*))
  88.                       
  89.               do
  90.               (cond ((eql ch #\newline)
  91.                  (push #\n some)
  92.                  (push #\\ some))
  93.                 ((eql ch #\tab)
  94.                  (push #\t some)
  95.                  (push #\\ some))
  96.                 (t (push ch some))))
  97.            (setq k (length some))
  98.            (setq some (append some
  99.                   (sloop for i below 20 for tem =
  100.                      nil 
  101.                      ;(read-char-no-hang)
  102.                      while tem collect tem)))
  103.            (terpri)
  104.            (sloop for v in some do (princ v))
  105.            (terpri)
  106.            (sloop for i from 2 below k do (princ #\space))
  107.            (princ "^")
  108.            
  109.            ;(sloop while (read-char-no-hang) )
  110.            )))
  111.       (terpri)
  112.       (throw-macsyma-top) 
  113.       )
  114.     ))
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121. ;;; (FIXNUM-CHAR-UPCASE c)
  122. ;;;
  123. ;;;  If its argument, which must be a fixnum, represents a lowercase 
  124. ;;;  character, the uppercase representation of that character is returned.
  125. ;;;  Otherwise, it returns its argument.
  126.  
  127. #+cl
  128. (DEFUN FIXNUM-CHAR-UPCASE (C)
  129.   (char-upcase c))
  130.  
  131. ;  (char-code (char-upcase (code-char c))))
  132.  
  133.  
  134. (DEFUN FIRSTCHARN (X)
  135.   #+NIL     (CHAR-CODE (CHAR (SYMBOL-NAME X) 0))
  136.   #+cl (aref (string x) 0)
  137.   #+MACLISP (GETCHARN X 1))
  138.  
  139. (DEFVAR *PARSE-STREAM*        ()        "input stream for Macsyma parser")
  140. (DEFVAR MACSYMA-OPERATORS    ()        "Macsyma operators structure")
  141. (DEFVAR *MREAD-PROMPT*        nil        "prompt used by MREAD")
  142. (DEFVAR *MREAD-EOF-OBJ* () "Bound by MREAD for use by MREAD-RAW")
  143.  
  144. (defun tyi-parse-int (stream eof)
  145.   (or *parse-window*
  146.       (progn (setq *parse-window* (make-list 25))
  147.          (setf (get '*parse-window* 'length) (length *parse-window*))
  148.          (nconc *parse-window* *parse-window*)))
  149.   (let ((tem (TYI stream eof)))
  150.     (setf (car *parse-window*) tem *parse-window*
  151.       (cdr *parse-window*))
  152.     (if (eql tem #\newline) (newline stream #\newline))
  153.     tem))
  154.  
  155.  
  156.  
  157. ;; We keep our own look-ahead state variable because the end-of-expression
  158. ;; is always a single character, and there is never need to UNTYI. --WRONG--wfs
  159.  
  160. ;(DEFVAR PARSE-TYIPEEK () "T if there is a peek character.")
  161. ;(DEFVAR PARSE-TYI     () "The peek character.")
  162. ;
  163. ;(DEFUN PARSE-TYIPEEK ()
  164. ;  (COND (PARSE-TYIPEEK PARSE-TYI)
  165. ;    ('ELSE
  166. ;     (SETQ PARSE-TYIPEEK T)
  167. ;     (SETQ PARSE-TYI (tyi-parse-int *PARSE-STREAM* -1)))))
  168.  
  169.  
  170. ;(DEFUN PARSE-TYI ( &aux answ)
  171. ;  (setq answ(COND (PARSE-TYIPEEK
  172. ;     (SETQ PARSE-TYIPEEK ())
  173. ;     PARSE-TYI)
  174. ;    ('ELSE
  175. ;     (TYI *PARSE-STREAM* -1))))
  176. ;  (princ answ) answ)
  177. ;
  178. ;
  179. ;(DEFUN PARSE-TYI ()
  180. ;  (COND (PARSE-TYIPEEK
  181. ;     (SETQ PARSE-TYIPEEK ())
  182. ;     PARSE-TYI)
  183. ;    ('ELSE
  184. ;     (tyi-parse-int *PARSE-STREAM* -1)
  185. ;     )))
  186.  
  187.  
  188.  
  189.  
  190. (DEFUN *MREAD-PROMPT* (OUT-STREAM CHAR)
  191.   CHAR
  192.   (FORMAT OUT-STREAM "~&~A" *MREAD-PROMPT*))
  193.   
  194. (DEFUN ALIASLOOKUP (OP)
  195.   (IF (SYMBOLP OP)
  196.       (OR (GET OP 'ALIAS) OP)
  197.       OP))
  198.  
  199.  
  200.  
  201. ;;;; Tokenizing
  202.  
  203. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  204. ;;;;;                                                                    ;;;;;
  205. ;;;;;                      The Input Scanner                             ;;;;;
  206. ;;;;;                                                                    ;;;;;
  207. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  208.  
  209. ;; gobble whitespace, recognize '#' comments..
  210. (DEFUN GOBBLE-WHITESPACE ( &aux saw-newline ch saw-other)
  211.   (DO () (NIL) ; Gobble whitespace
  212.       (setq ch (PARSE-TYIPEEK))
  213.       (cond ((eql ch #\newline)
  214.          (setq saw-other nil)
  215.          (setq saw-newline t))
  216.         ((IMEMBER ch
  217.           '(#\TAB #\SPACE #\Linefeed #\return ;#\control-C
  218.               #\Page))
  219.          (setq saw-other t))
  220.         ;; allow comments to be lines which are whitespace and then
  221.         ;; a '#' character.
  222.         ;; recognize
  223.         ;; # 234 "jim.mac"
  224.         ;; to set the current line information to be line 234 of jim.mac
  225.         ((and (eql ch #\#) saw-newline)
  226.          (let ((li (read-line *parse-stream* nil)))
  227.            (declare (type (vector #.(array-element-type "a")) li))
  228.            (unread-char #\newline  *parse-stream*)
  229.            (setq parse-tyipeek nil)
  230.            (if (not saw-other) (grab-line-number li *parse-stream*))))
  231.         (t  (return t)))
  232.      (parse-tyi)
  233.      ))
  234.  
  235. (DEFUN READ-COMMAND-TOKEN (OBJ)
  236.   (GOBBLE-WHITESPACE)
  237.   (READ-COMMAND-TOKEN-AUX OBJ))
  238.  
  239. (defun ch-minusp (z)
  240.   (and (numberp z) (< z 0)))
  241.  
  242. (defun safe-assoc (item lis)
  243.   "maclisp would not complain about (car 3) it gives nil"
  244.   (sloop for v in lis
  245.     when (and (consp v)
  246.           (equal (car v) item))
  247.     do
  248.     (return v)))
  249. ;
  250. ;(DEFUN READ-COMMAND-TOKEN-AUX (OBJ)
  251. ;  (IF (NOT (CDDR OBJ))
  252. ;      (CADADR OBJ)
  253. ;      (LET ((C (PARSE-TYIPEEK)))
  254. ;    #-cl(DECLARE (FIXNUM C))
  255. ;    (IF  #+cl (not( ch-minusp c))
  256. ;             #-cl
  257. ;      (NOT (MINUSP C))
  258. ;        (LET ((ANSWER (OR (safe-ASSOC C (CDDR OBJ)) (and (listp obj)(listp (cdr obj))
  259. ;                                 (CADR OBJ)))))
  260. ;          (IF (EQ (and (listp answer)(CAR ANSWER)) 'ANS)
  261. ;          (CADR ANSWER)
  262. ;          (PARSE-TYI)
  263. ;          (READ-COMMAND-TOKEN-AUX ANSWER)))))))
  264.  
  265.  
  266. ;(setq macsyma-operators '(NIL (ANS NIL) (#\a #\b #\c (ANS |$abc|))     (#\e (ANS |$e|) (#\f (ANS |$ef|) (#\g (ANS |$efg|))))     (#\; (ANS |$;|))))              
  267. ;;(NIL (ANS NIL) (#\a #\b #\c (ANS |$abc|))
  268. ;;     (#\e (ANS |$e|) (#\f (ANS |$ef|) (#\g (ANS |$efg|)))))
  269.  
  270.  
  271. ;; list contains an atom, only check
  272. ;; (parser-assoc 1 '(2 1 3)) ==>(1 3)
  273. ;; (parser-assoc 1 '(2 (1 4) 3)) ==>(1 4)
  274.  
  275. (defun parser-assoc (c lis )
  276.   (sloop for v on lis
  277.      do
  278.      (cond ((consp (car v))
  279.         (if (eq (caar v) c)
  280.             (return (car v))))
  281.            ((eql (car v) c)
  282.         (return v)))))
  283.  
  284. ;; we need to be able to unparse-tyi an arbitrary number of
  285. ;; characters, since if you do
  286. ;; PREFIX("ABCDEFGH");
  287. ;; then ABCDEFGA should read as a symbol.
  288. ;; 99% of the time we dont have to unparse-tyi, and so there will
  289. ;; be no consing...
  290.  
  291. (defvar *parse-tyi* nil)
  292. (defun parse-tyi ()
  293.   (let ((tem  *parse-tyi*))
  294.     (cond ((null tem)
  295.        (tyi-parse-int *PARSE-STREAM* -1))
  296.       ((atom tem)
  297.        (setq *parse-tyi* nil)
  298.        tem)
  299.       (t ;;consp
  300.        (setq *parse-tyi* (cdr tem))
  301.        (car tem)))))
  302.  
  303. ;; read one character but leave it there. so next parse-tyi gets it
  304. (defun parse-tyipeek ()
  305.   (let ((tem  *parse-tyi*))
  306.     (cond ((null tem)
  307.        (setq *parse-tyi* (tyi-parse-int *parse-stream* -1)))
  308.       ((atom tem) tem)
  309.       (t (car tem)))))
  310.  
  311. ;; push characters back on the stream
  312. (defun unparse-tyi (c)
  313.   (let ((tem  *parse-tyi*))
  314.     (cond ((null tem)
  315.        (setq *parse-tyi* c))
  316.       (t (setq *parse-tyi* (cons c tem))))))
  317.  
  318.  
  319. ;;I know that the tradition says there should be no comments
  320. ;;in tricky code in maxima.  However the operator parsing
  321. ;;gave me a bit of trouble.   It was incorrect because
  322. ;;it could not handle things produced by the extensions
  323. ;;the following was broken for prefixes 
  324.  
  325.  
  326. (defun read-command-token-aux (obj)
  327.   (let* (result
  328.      (ch (parse-tyipeek))
  329.      (lis (if (eql ch -1) nil  (parser-assoc (char-upcase ch) obj))))
  330.     (cond ((null lis) 
  331.        nil)
  332.       (t
  333.        (parse-tyi)
  334.        (cond ((atom (cadr lis))
  335.        ;; INFIX("ABC"); puts into macsyma-operators
  336.        ;;something like: (#\A #\B #\C (ANS |$ABC|))
  337.        ;; ordinary things are like:
  338.        ;; (#\< (ANS $<) (#\= (ANS $<=)))
  339.        ;; where if you fail at the #\< #\X
  340.        ;; stage, then the previous step was permitted.
  341.           (setq result (read-command-token-aux (list (cdr lis) ))))
  342.          ((null (cddr lis))
  343.           ;; lis something like (#\= (ANS $<=))
  344.           ;; and this says there are no longer operators
  345.           ;; starting with this.
  346.           (setq result
  347.             (and (eql (car (cadr lis)) 'ans)
  348.                   (cadr (cadr lis)))))
  349.          (t
  350.           (let ((res   (and (eql (car (cadr lis)) 'ans)
  351.                     (cadr (cadr lis))))
  352.             (com-token (read-command-token-aux (cddr lis) )))
  353.             (setq result (or com-token res 
  354.                      (read-command-token-aux
  355.                       (list (cadr lis))))))
  356.             ))
  357.          (or result (unparse-tyi ch))
  358.          result))))
  359.  
  360.  
  361. (DEFUN SCAN-MACSYMA-TOKEN ()
  362.   ;; note that only $-ed tokens are GETALIASed.
  363.   (let ((tem (CONS '#\$ (SCAN-TOKEN T))))
  364.     (setq tem (if $bothcases (bothcase-implode tem) (implode1 tem nil)))
  365.   (GETALIAS tem)))
  366.  
  367. (DEFUN SCAN-LISP-TOKEN ()
  368.   (let ((scan (SCAN-TOKEN ())))
  369.   (IMPLODE1 scan (not (member #\| scan)))
  370.   ))
  371. (DEFUN SCAN-keyword-TOKEN ()
  372.   (let ((*package* 'keyword)) (IMPLODE (SCAN-TOKEN ()))))
  373.  
  374. (defvar $bothcases t)
  375. (DEFUN SCAN-TOKEN (FLAG)
  376.   (DO ((C (PARSE-TYIPEEK) (PARSE-TYIPEEK))
  377.        (L () (CONS C L)))
  378.       ((AND FLAG (NOT (OR (ASCII-NUMBERP C) (ALPHABETP C) (char= C #.back-slash-char)))) ;;#/\
  379.        (NREVERSE (OR L (NCONS (PARSE-TYI))))) ; Read at least one char ...
  380.     (IF (char= (PARSE-TYI) #. back-slash-char);; #/\
  381.     (SETQ C (PARSE-TYI))
  382.     (or $bothcases  (SETQ C (FIXNUM-CHAR-UPCASE C))))
  383.     (SETQ FLAG T)))
  384.  
  385. (DEFUN SCAN-LISP-STRING () (INTERN (SCAN-STRING)))
  386.  
  387. (DEFUN SCAN-MACSYMA-STRING () (INTERN (SCAN-STRING #\&)))
  388.  
  389. (defvar *scan-string-buffer*
  390.   nil)
  391.  
  392. (DEFUN SCAN-STRING (&optional init)
  393.   (let ((buf (or *scan-string-buffer*
  394.          (setq *scan-string-buffer*
  395.                (make-array 50 :element-type ' #.(array-element-type "abc")
  396.                    :fill-pointer 0 :adjustable t))))
  397.     (*scan-string-buffer* nil))
  398.     (setf (fill-pointer buf) 0)
  399.     (when init (vector-push-extend (coerce init 'character) buf))
  400.     (DO ((C (PARSE-TYIPEEK) (PARSE-TYIPEEK)))
  401.     ((cond ((eql c -1))
  402.            ((char= c #. double-quote-char)
  403.         (parse-tyi) t))
  404.      (copy-seq buf))
  405.       (IF (char= (PARSE-TYI) #. back-slash-char) ;; #/\ )
  406.       (SETQ C (PARSE-TYI)))
  407.       #-cl
  408.       (vector-push-extend (code-char c) buf)
  409.       #+cl
  410.       (vector-push-extend c  buf)
  411.       )))
  412.  
  413. (defvar *string-register* (make-array 100 :fill-pointer 0 :adjustable t :element-type '#.(array-element-type "a")))
  414. (defun readlist (lis)
  415.   (setf (fill-pointer *string-register*) 0)
  416.   (sloop for u in lis do (vector-push-extend u *string-register*))
  417.   (read-from-string   *string-register*))
  418.  
  419.  
  420. (DEFUN MAKE-NUMBER (DATA)
  421.   (SETQ DATA (NREVERSE DATA))
  422.   (IF (NOT (EQUAL (NTH 3. DATA) '(#\B)))
  423.       (READLIST (APPLY #'APPEND DATA))
  424.       ;; For bigfloats, turn them into rational numbers then convert to bigfloat
  425.       ($BFLOAT `((MTIMES) ((MPLUS) ,(READLIST (or (FIRST DATA) '(#\0)))
  426.                    ((MTIMES) ,(READLIST (or (THIRD DATA) '(#\0)))
  427.                          ((MEXPT) 10. ,(f- (LENGTH (THIRD DATA))))))
  428.               ((MEXPT) 10. ,(FUNCALL (IF (char= (FIRST (FIFTH DATA)) #\-) #'- #'+)
  429.                          (READLIST (SIXTH DATA))))))))
  430.  
  431. (DEFUN SCAN-DIGITS (DATA CONTINUATION? CONTINUATION)
  432.   (DO ((C (PARSE-TYIPEEK) (PARSE-TYIPEEK))
  433.        (L () (CONS C L)))
  434.       ((NOT (ASCII-NUMBERP C))
  435.        (COND ((IMEMBER C CONTINUATION?)
  436.           (FUNCALL CONTINUATION (LIST* (NCONS (FIXNUM-CHAR-UPCASE
  437.                            (PARSE-TYI)))
  438.                        (NREVERSE L)
  439.                        Data)
  440.                    ))
  441.          (T
  442.           (MAKE-NUMBER (CONS (NREVERSE L) DATA)))))
  443.     (PARSE-TYI)))
  444.  
  445. #+nil
  446. (DEFUN SCAN-NUMBER-BEFORE-DOT (DATA)
  447.   (SCAN-DIGITS DATA '(#. period-char) #'SCAN-NUMBER-AFTER-DOT))
  448.  
  449. (DEFUN SCAN-NUMBER-AFTER-DOT (DATA)
  450.   (SCAN-DIGITS DATA '(#\E #\e #\B #\b #\D #\d #\S #\s) #'SCAN-NUMBER-EXPONENT))
  451.  
  452. (DEFUN SCAN-NUMBER-EXPONENT (DATA)
  453.   (PUSH (NCONS (IF (OR (char= (PARSE-TYIPEEK) #\+)
  454.                (char= (PARSE-TYIPEEK) #\-))
  455.            (PARSE-TYI)
  456.            #\+))
  457.     DATA)
  458.   (SCAN-DIGITS DATA () ()))
  459.  
  460.  
  461. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  462. ;;;;;                                                                    ;;;;;
  463. ;;;;;                    The Expression Parser                           ;;;;;
  464. ;;;;;                                                                    ;;;;;
  465. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  466.  
  467. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  468. ;;;                                                                      ;;;
  469. ;;;    Based on a theory of parsing presented in:                       ;;;
  470. ;;;                                                                      ;;;
  471. ;;;        Pratt, Vaughan R., ``Top Down Operator Precedence,''         ;;;
  472. ;;;        ACM Symposium on Principles of Programming Languages         ;;;
  473. ;;;        Boston, MA; October, 1973.                                   ;;;
  474. ;;;                                                                      ;;;
  475. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  476.  
  477. ;;;    Implementation Notes ....
  478. ;;;
  479. ;;;    JPG    Chars like ^A, ^B, ... get left around after interrupts and
  480. ;;;        should be thrown away by the scanner if not used as editting
  481. ;;;        commands.
  482. ;;;
  483. ;;;    KMP    There is RBP stuff in DISPLA, too. Probably this sort of
  484. ;;;        data should all be in one place somewhere.
  485. ;;;    
  486. ;;;    KMP    Maybe the parser and/or scanner could use their own GC scheme 
  487. ;;;        to recycle conses used in scan/parse from line to line which 
  488. ;;;        really ought not be getting dynamically discarded and reconsed.
  489. ;;;            Alternatively, we could call RECLAIM explicitly on certain 
  490. ;;;        pieces of structure which get used over and over. A 
  491. ;;;        local-reclaim abstraction may want to be developed since this
  492. ;;;        stuff will always be needed, really. On small-address-space
  493. ;;;        machines, this could be overridden when the last DYNAMALLOC 
  494. ;;;        GC barrier were passed (indicating that space was at a premium
  495. ;;;        -- in such case, real RECLAIM would be more economical -- or 
  496. ;;;        would the code to control that be larger than the area locked 
  497. ;;;        down ...?)
  498. ;;;
  499. ;;;    KMP    GJC has a MAKE-EVALUATOR type package which could probably
  500. ;;;        replace the CALL-IF-POSSIBLE stuff used here.
  501. ;;;             [So it was written, so it was done. -gjc]
  502. ;;;
  503. ;;;    KMP    DEFINE-SYMBOL and KILL-OPERATOR need to be redefined.
  504. ;;;        Probably these shouldn't be defined in this file anyway.
  505. ;;;
  506. ;;;    KMP    The relationship of thisfile to SYNEX needs to be thought
  507. ;;;        out more carefully.
  508. ;;;
  509. ;;;    GJC    Need macros for declaring INFIX, PREFIX, etc ops
  510. ;;;
  511. ;;;    GJC    You know, PARSE-NARY isn't really needed it seems, since 
  512. ;;;        the SIMPLIFIER makes the conversion of
  513. ;;;            ((MTIMES) ((MTIMES) A B) C) => ((MTIMES) A B C)
  514. ;;;        I bet you could get make "*" infix and nobody would 
  515. ;;;        ever notice.
  516.  
  517. ;;; The following terms may be useful in deciphering this code:
  518. ;;;
  519. ;;; NUD -- NUll left Denotation (op has nothing to its left (prefix))
  520. ;;; LED -- LEft Denotation    (op has something to left (postfix or infix))
  521. ;;;
  522. ;;; LBP -- Left Binding Power  (the stickiness to the left)
  523. ;;; RBP -- Right Binding Power (the stickiness to the right)
  524. ;;;
  525.  
  526.  
  527. ;;;; Macro Support
  528.  
  529. ;; "First character" and "Pop character"
  530.  
  531. (DEFVAR SCAN-BUFFERED-TOKEN (LIST NIL)
  532.   "put-back buffer for scanner, a state-variable of the reader")
  533.  
  534. (DEFUN PEEK-ONE-TOKEN ()
  535.   (PEEK-ONE-TOKEN-G NIL NIL))
  536.  
  537. (DEFUN PEEK-ONE-TOKEN-G (EOF-OK? EOF-OBJ)
  538.   (cond
  539.    ((CAR SCAN-BUFFERED-TOKEN)
  540.     (CDR SCAN-BUFFERED-TOKEN))
  541.    (t (RPLACD SCAN-BUFFERED-TOKEN (SCAN-ONE-TOKEN-G EOF-OK? EOF-OBJ))
  542.       (CDR (RPLACA SCAN-BUFFERED-TOKEN T)))))
  543.  
  544. (DEFUN SCAN-ONE-TOKEN ()
  545.   (SCAN-ONE-TOKEN-G NIL NIL))
  546.  
  547. (DEFUN SCAN-ONE-TOKEN-G (EOF-OK? EOF-OBJ)
  548.   (COND ((CAR SCAN-BUFFERED-TOKEN)
  549.      (RPLACA SCAN-BUFFERED-TOKEN ())
  550.      (CDR SCAN-BUFFERED-TOKEN))
  551.     ((READ-COMMAND-TOKEN MACSYMA-OPERATORS))
  552.     (T
  553.      (LET ((TEST (PARSE-TYIPEEK)))
  554.        (cond  ((eql test -1.)
  555.            (PARSE-TYI)
  556.            (IF EOF-OK? EOF-OBJ
  557.                (MAXIMA-ERROR "End of file while scanning expression")))
  558.           ((eql test forward-slash-char) ;;#//)
  559.            (PARSE-TYI)
  560.            (COND ((char= (PARSE-TYIPEEK) #\*)
  561.               (GOBBLE-COMMENT)
  562.               (SCAN-ONE-TOKEN-G EOF-OK? EOF-OBJ))
  563.              (T '#-cl $// #+cl $/ )))
  564.           ((eql test #. period-char) (PARSE-TYI)    ; Read the dot
  565.            (IF (ASCII-NUMBERP (PARSE-TYIPEEK))
  566.                (SCAN-NUMBER-AFTER-DOT (LIST (NCONS #. period-char) NIL))
  567.                '|$.|))
  568.           ((eql test double-quote-char );;#/")
  569.            (PARSE-TYI)
  570.            (SCAN-MACSYMA-STRING))
  571.           ((eql test #\?)
  572.            (PARSE-TYI)
  573.            (COND ((char= (PARSE-TYIPEEK) double-quote-char );;#/")
  574.               (PARSE-TYI)
  575.               (SCAN-LISP-STRING))
  576.              ((char= (parse-tyipeek) #\:)
  577.               (scan-keyword-token))
  578.              (t
  579.               (SCAN-LISP-TOKEN))))
  580.           (T
  581.            (IF (ASCII-NUMBERP TEST)
  582.                (SCAN-NUMBER-BEFORE-DOT ())
  583.                (SCAN-MACSYMA-TOKEN))))))))
  584.  
  585. ;; nested comments are permitted.
  586. (defun gobble-comment ()
  587.   (prog (c depth)
  588.     (setq depth 1)
  589.      read
  590.     (setq c (parse-tyipeek))
  591.     (parse-tyi)
  592.     (cond ((= depth 0) (return t)))
  593.     (cond ((and (numberp c) (< c 0))(error "end of file in comment"))
  594.           ((char= c #\*)
  595.            (cond ((char= (parse-tyipeek) #. forward-slash-char)
  596.               (decf depth) 
  597.               (parse-tyi)
  598.               (cond ((= depth 0) (return t)))
  599.               (go read))))
  600.           ((char= c #.forward-slash-char)
  601.            (cond ((char= (parse-tyipeek) #\*) 
  602.               (incf depth) (parse-tyi)
  603.               (go read)))))
  604.         (go read))
  605.   )
  606.  
  607. (defun scan-number-rest (data)
  608.   (let ((c (caar data)))
  609.     (cond ((imember c '(#. period-char))
  610.        ;; We found a dot
  611.        (scan-number-after-dot data))
  612.       ((imember c '(#\E #\e #\B #\b #\D #\d #\S #\s))
  613.        ;; Dot missing but found exponent marker.  Fake it.
  614.        (setf data (push (ncons #\.) (rest data)))
  615.        (push (ncons #\0) data)
  616.        (push (ncons c) data)
  617.        (scan-number-exponent data)))))
  618.  
  619. (defun scan-number-before-dot (data)
  620.   (scan-digits data '(#. period-char #\E #\e #\B #\b #\D #\d #\S #\s)
  621.            #'scan-number-rest))
  622.  
  623.     
  624.  
  625. (DEFMACRO FIRST-C () '(PEEK-ONE-TOKEN))
  626. (DEFMACRO POP-C   () '(SCAN-ONE-TOKEN))
  627.  
  628.  
  629.  
  630. (DEFUN MSTRINGP (X)
  631.   (AND (SYMBOLP X) (char= (FIRSTCHARN X) #\&)))
  632.  
  633.  
  634. ;(DEFUN AMPERCHK (NAME)
  635. ;  (IF (MSTRINGP NAME) (DOLLARIFY-NAME NAME) NAME))
  636. ;;see suprv1
  637.  
  638. (DEFUN INHERIT-PROPL (OP-TO OP-FROM GETL)
  639.   (LET ((PROPL (GETL OP-FROM GETL)))
  640.     (IF PROPL
  641.     (PROGN (REMPROP OP-TO (CAR PROPL))
  642.            (PUTPROP OP-TO (CADR PROPL) (CAR PROPL)))
  643.     (INHERIT-PROPL OP-TO
  644.                (MAXIMA-ERROR (LIST "has no" GETL "properties.")
  645.                   OP-FROM
  646.                   'WRNG-TYPE-ARG)
  647.                GETL))))
  648.  
  649.  
  650. ;;; (NUD <op>)
  651. ;;; (LED <op> <left>)
  652. ;;;
  653. ;;;  <op>   is the name of the operator which was just popped.
  654. ;;;  <left> is the stuff to the left of the operator in the LED case.
  655. ;;;
  656.  
  657. (eval-when (eval compile load)
  658.  
  659.  
  660. #+already-expanded-below
  661. (DEF-PROPL-CALL NUD (OP)
  662.   (IF (OPERATORP OP)
  663.       ;; If first element is an op, it better have a NUD
  664.       (MREAD-SYNERR "~A is not a prefix operator" (MOPSTRIP OP))
  665.       ;; else take it as is.
  666.       (CONS '$ANY OP)))
  667. ;;begin expansion
  668. (DEFMACRO DEF-NUD-EQUIV (OP EQUIV)
  669.    (LIST 'PUTPROP (LIST 'QUOTE OP) (LIST 'FUNCTION EQUIV)
  670.           (LIST 'QUOTE 'NUD)))
  671. (DEFMACRO NUD-PROPL () ''(NUD))
  672.   (DEFMACRO DEF-NUD-FUN (OP-NAME OP-L . BODY)
  673.     (LIST* 'DEFUN-PROP (LIST* OP-NAME 'NUD 'NIL) OP-L BODY))
  674. (DEFUN NUD-CALL (OP)
  675.     (LET ((TEM (AND (SYMBOLP OP) (GETL OP '(NUD)))) res)
  676.      (setq res     
  677.            (IF (NULL TEM)
  678.            (IF (OPERATORP OP)
  679.                (MREAD-SYNERR "~A is not a prefix operator"
  680.                      (MOPSTRIP OP))
  681.                (CONS '$ANY OP))
  682.            (FUNCALL (CADR TEM) OP)))
  683.      res
  684.      ))
  685. ;;end expansion 
  686.  
  687. ;;following defines def-led-equiv led-propl def-led-fun led-call
  688. #+already-expanded-below
  689. (DEF-PROPL-CALL LED (OP L)
  690.   (MREAD-SYNERR "~A is not an infix operator" (MOPSTRIP OP)))
  691. )
  692. ;;begin expansion
  693. (DEFMACRO DEF-LED-EQUIV (OP EQUIV)
  694.     (LIST 'PUTPROP (LIST 'QUOTE OP) (LIST 'FUNCTION EQUIV)
  695.           (LIST 'QUOTE 'LED)))
  696. (DEFMACRO LED-PROPL () ''(LED))
  697. (DEFMACRO DEF-LED-FUN (OP-NAME OP-L . BODY)
  698.     (LIST* 'DEFUN-PROP (LIST* OP-NAME 'LED 'NIL) OP-L BODY))
  699. (DEFUN LED-CALL (OP L)
  700.    
  701.     (LET ((TEM (AND (SYMBOLP OP) (GETL OP '(LED)))) res)
  702.      (setq res
  703.       (IF (NULL TEM)
  704.           (MREAD-SYNERR "~A is not an infix operator" (MOPSTRIP OP))
  705.           (FUNCALL (CADR TEM) OP L))
  706.       )
  707.      res
  708.       ))
  709. ;;end expansion
  710.  
  711. ;;; (DEF-NUD (op lbp rbp) bvl . body)
  712. ;;;
  713. ;;;  Defines a procedure for parsing OP as a prefix operator.
  714. ;;;
  715. ;;;  OP  should be the name of the symbol as a string or symbol.
  716. ;;;  LBP is an optional left  binding power for the operator.
  717. ;;;  RBP is an optional right binding power for the operator.
  718. ;;;  BVL must contain exactly one variable, which the compiler will not
  719. ;;;      complain about if unused, since it will rarely be of use anyway.
  720. ;;;      It will get bound to the operator being parsed.
  721. ;;;  lispm:Optional args not allowed in release 5 allowed, necessary afterwards..
  722.  
  723. #+cl
  724. (DEFMACRO DEF-NUD ((OP . LBP-RBP) BVL . BODY)
  725.   (let (( lbp (nth 0 lbp-rbp))
  726.     ( rbp (nth 1 lbp-rbp)))
  727.     `(PROGN 'COMPILE       ,(MAKE-PARSER-FUN-DEF OP 'NUD BVL BODY)
  728.         (SET-LBP-AND-RBP ',OP ',LBP ',RBP))))
  729.  
  730. #-cl
  731. (DEFMACRO DEF-NUD ((OP #+nil &OPTIONAL LBP RBP) BVL . BODY)
  732.   `(PROGN 'COMPILE       ,(MAKE-PARSER-FUN-DEF OP 'NUD BVL BODY)
  733.       (SET-LBP-AND-RBP ',OP ',LBP ',RBP)))
  734.  
  735. (DEFUN SET-LBP-AND-RBP (OP LBP RBP)
  736.   (COND ((NOT (consp OP))
  737.      (LET ((EXISTING-LBP (GET OP 'LBP))
  738.            (EXISTING-RBP (GET OP 'RBP)))
  739.        (COND ((NOT LBP)
  740.           (COMMENT IGNORE OMITTED ARG))
  741.          ((NOT EXISTING-LBP)
  742.           (PUTPROP OP LBP 'LBP))
  743.          ((NOT (EQUAL EXISTING-LBP LBP))
  744.           (MAXIMA-ERROR "Incompatible LBP's defined for this operator" OP)))
  745.        (COND ((NOT RBP)
  746.           (COMMENT IGNORE OMITTED ARG))
  747.          ((NOT EXISTING-RBP)
  748.           (PUTPROP OP RBP 'RBP))
  749.          ((NOT (EQUAL EXISTING-RBP RBP))
  750.           (MAXIMA-ERROR "Incompatible RBP's defined for this operator" OP)))))
  751.     ('ELSE
  752.      (MAPCAR #'(LAMBDA (X) (SET-LBP-AND-RBP X LBP RBP))
  753.          OP))))
  754.                    
  755.  
  756. ;;; (DEF-LED (op lbp rbp) bvl . body)
  757. ;;;
  758. ;;;  Defines a procedure for parsing OP as an infix or postfix operator.
  759. ;;;
  760. ;;;  OP  should be the name of the symbol as a string or symbol.
  761. ;;;  LBP is an optional left  binding power for the operator.
  762. ;;;  RBP is an optional right binding power for the operator.
  763. ;;;  BVL must contain exactly two variables, the first of which the compiler
  764. ;;;       will not complain about if unused, since it will rarely be of use
  765. ;;;      anyway. Arg1 will get bound to the operator being parsed. Arg2 will
  766. ;;;      get bound to the parsed structure which was to the left of Arg1.
  767.  
  768.  
  769. #+cl
  770. (DEFMACRO DEF-LED((OP . LBP-RBP) BVL . BODY)
  771.   (let (( lbp (nth 0 lbp-rbp))
  772.     ( rbp (nth 1 lbp-rbp)))
  773.     `(PROGN 'COMPILE
  774.         ,(MAKE-PARSER-FUN-DEF  OP 'LED BVL BODY)
  775.         (SET-LBP-AND-RBP ',OP ',LBP ',RBP))))
  776.  
  777. #-cl
  778. (DEFMACRO DEF-LED ((OP #+(or cl NIL) &OPTIONAL LBP RBP) BVL . BODY)
  779.   `(PROGN 'COMPILE
  780.       ,(MAKE-PARSER-FUN-DEF  OP 'LED BVL BODY)
  781.       (SET-LBP-AND-RBP ',OP ',LBP ',RBP)))
  782.  
  783. (DEFMACRO DEF-COLLISIONS (OP &REST ALIST)
  784.   (LET ((KEYS (DO ((I  1.    (#+cl ash #-cl LSH I 1.))
  785.            (LIS  ALIST (CDR LIS))
  786.            (NL ()    (CONS (CONS (CAAR LIS) I) NL)))
  787.           ((NULL LIS) NL))))
  788.     `(PROGN 'COMPILE
  789.        (DEFPROP ,OP ,(let #+lispm ((default-cons-area working-storage-area))
  790.               #-lispm nil
  791.                (copy-tree KEYS )) KEYS)
  792.        ,@(MAPCAR #'(LAMBDA (DATA)
  793.              `(DEFPROP ,(CAR DATA)
  794.                    ,(DO ((I 0 (LOGIOR I  (CDR (ASSQ (CAR LIS) KEYS))))
  795.                      (LIS (CDR DATA) (CDR LIS)))
  796.                     ((NULL LIS) I))
  797.                    ,OP))
  798.          ALIST))))
  799.  
  800.  
  801.  
  802. (DEFUN COLLISION-LOOKUP (OP ACTIVE-BITMASK KEY-BITMASK)
  803.   (LET ((RESULT (LOGAND ACTIVE-BITMASK KEY-BITMASK)))
  804.     (IF (NOT (ZEROP RESULT))
  805.     (DO ((L (GET OP 'KEYS) (CDR L)))
  806.         ((NULL L) (PARSE-BUG-ERR 'COLLISION-CHECK))
  807.       (IF (NOT (ZEROP (LOGAND RESULT (CDAR L))))
  808.           (RETURN (CAAR L)))))))
  809.  
  810. (DEFUN COLLISION-CHECK (OP ACTIVE-BITMASK KEY)
  811.   (LET ((KEY-BITMASK (GET KEY OP)))
  812.     (IF (NOT KEY-BITMASK)
  813.     (MREAD-SYNERR "~A is an unknown keyword in a ~A statement."
  814.               (MOPSTRIP KEY) (MOPSTRIP OP)))
  815.     (LET ((COLLISION (COLLISION-LOOKUP OP ACTIVE-BITMASK KEY-BITMASK)))
  816.       (IF COLLISION
  817.       (IF (EQ COLLISION KEY)
  818.           (MREAD-SYNERR "This ~A's ~A slot is already filled."
  819.                 (MOPSTRIP OP)
  820.                 (MOPSTRIP KEY))
  821.           (MREAD-SYNERR "A ~A cannot have a ~A with a ~A field."
  822.                 (MOPSTRIP OP)
  823.                 (MOPSTRIP KEY)
  824.                 (MOPSTRIP COLLISION))))
  825.       (LOGIOR (CDR (ASSQ KEY (GET OP 'KEYS))) ACTIVE-BITMASK))))
  826.       
  827.  
  828.  
  829. ;;;; Data abstraction
  830.  
  831. ;;; LBP = Left Binding Power
  832. ;;;
  833. ;;; (LBP <op>)         - reads an operator's Left Binding Power
  834. ;;; (DEF-LBP <op> <val>) - defines an operator's Left Binding Power
  835.  
  836. (DEFMFUN LBP (LEX) (COND ((safe-GET LEX 'LBP)) (T 200.)))
  837.  
  838. (DEFMACRO DEF-LBP (SYM VAL) `(DEFPROP ,SYM ,VAL LBP))
  839.  
  840. ;;; RBP = Right Binding Power
  841. ;;;
  842. ;;; (RBP <op>)         - reads an operator's Right Binding Power
  843. ;;; (DEF-RBP <op> <val>) - defines an operator's Right Binding Power
  844.  
  845. (DEFMFUN RBP (LEX) (COND ((safe-GET LEX 'RBP)) (T 200.)))
  846.  
  847. (DEFMACRO DEF-RBP (SYM VAL) `(DEFPROP ,SYM ,VAL RBP))
  848.  
  849. (DEFMACRO DEF-MATCH (X M) `(DEFPROP ,X ,M MATCH))
  850.  
  851. ;;; POS = Part of Speech!
  852. ;;; 
  853. ;;; (LPOS <op>)
  854. ;;; (RPOS <op>)
  855. ;;; (POS  <op>)
  856. ;;;
  857.  
  858. (DEFUN LPOS (OP) (COND ((safe-GET OP 'LPOS)) (T '$ANY)))
  859. (DEFUN RPOS (OP) (COND ((safe-GET OP 'RPOS)) (T '$ANY)))
  860. (DEFUN POS (OP) (COND ((safe-GET OP 'POS)) (T '$ANY)))
  861.  
  862. (DEFMACRO DEF-POS  (OP POS) `(DEFPROP ,OP ,POS  POS))
  863. (DEFMACRO DEF-RPOS (OP POS) `(DEFPROP ,OP ,POS RPOS))
  864. (DEFMACRO DEF-LPOS (OP POS) `(DEFPROP ,OP ,POS LPOS))
  865.  
  866. ;;; MHEADER
  867.  
  868. (DEFUN MHEADER (OP) (add-lineinfo (OR (safe-GET OP 'MHEADER) (NCONS OP))))
  869.  
  870. (DEFMACRO DEF-MHEADER (OP HEADER) `(DEFPROP ,OP ,HEADER MHEADER))
  871.  
  872.  
  873. (DEFMVAR $PARSEWINDOW 10.
  874.      "The maximum number of 'lexical tokens' that are printed out on
  875. each side of the error-point when a syntax (parsing) MAXIMA-ERROR occurs.  This
  876. option is especially useful on slow terminals.  Setting it to -1 causes the
  877. entire input string to be printed out when an MAXIMA-ERROR occurs."
  878.      FIXNUM)
  879.  
  880.  
  881.  
  882. ;;;; Misplaced definitions
  883.  
  884. (DEFMACRO DEF-OPERATORP ()
  885.   `(DEFMFUN OPERATORP (LEX)
  886.      (AND (SYMBOLP LEX) (GETL LEX '(,@(NUD-PROPL) ,@(LED-PROPL))))))
  887.  
  888. (DEF-OPERATORP)
  889.  
  890. (DEFMACRO DEF-OPERATORP1 ()
  891.   ;Defmfun -- used by SYNEX if not others.
  892.   `(DEFMFUN OPERATORP1 (LEX)
  893.      ;; Referenced outside of package: OP-SETUP, DECLARE1
  894.      ;; Use for truth value only, not for return-value.
  895.      (AND (SYMBOLP LEX) (GETL LEX '(LBP RBP ,@(NUD-PROPL) ,@(LED-PROPL))))))
  896.  
  897. (DEF-OPERATORP1)
  898.  
  899.  
  900. ;;;; The Macsyma Parser
  901.  
  902. ;;; (MREAD) with arguments compatible with losing maclisp READ style.
  903. ;;;
  904. ;;; Returns a parsed form of tokens read from stream.
  905. ;;;
  906. ;;; If you want rubout processing, be sure to call some stream which knows
  907. ;;; about such things. Also, I'm figuring that the PROMPT will be
  908. ;;; an atribute of the stream which somebody can hack before calling
  909. ;;; MREAD if he wants to.
  910.  
  911. #+Lispm
  912. (DEFUN READ-APPLY (F READ-ARGS &AUX WHICH-OPERS)
  913.   (MULTIPLE-VALUE-BIND (STREAM EOF)
  914.                (SI:DECODE-READ-ARGS READ-ARGS)
  915.  
  916.     (SETQ WHICH-OPERS (FUNCALL STREAM ':WHICH-OPERATIONS))
  917.     (IF (MEMQ ':RUBOUT-HANDLER WHICH-OPERS)
  918.     (FUNCALL STREAM ':RUBOUT-HANDLER '((:PROMPT *MREAD-PROMPT*))
  919.          F STREAM EOF)
  920.     (FUNCALL F STREAM EOF))))
  921.  
  922. #+Maclisp
  923. (DEFUN READ-APPLY (F READ-ARGS &AUX WHICH-OPERS)
  924.   (LET ((STREAM (CAR READ-ARGS))
  925.     (EOF (CADR READ-ARGS)))
  926.     ;; apply the correction.
  927.     (COND ((AND (NULL (CDR READ-ARGS))
  928.         (NOT (OR (EQ STREAM T)
  929.              (SFAP STREAM)
  930.              (FILEP STREAM))))
  931.        (SETQ STREAM NIL EOF STREAM)))
  932.     (COND ((EQ STREAM T)
  933.        (SETQ STREAM TYI))
  934.       ((EQ STREAM NIL)
  935.        (IF ^Q (SETQ STREAM INFILE) (SETQ STREAM TYI))))
  936.     (SETQ WHICH-OPERS (AND (SFAP STREAM)
  937.                (SFA-CALL STREAM 'WHICH-OPERATIONS NIL)))
  938.     (IF (MEMQ 'RUBOUT-HANDLER WHICH-OPERS)
  939.     (SFA-CALL STREAM 'RUBOUT-HANDLER F)
  940.     (FUNCALL F STREAM EOF))))
  941.  
  942. (defvar *current-line-info* nil)
  943.  
  944. ;;Important for lispm rubout handler
  945. (DEFUN MREAD (&REST READ-ARGS)
  946.   #+NIL (let ((*mread-prompt-internal* *mread-prompt*)
  947.           (si:*ttyscan-dispatch-table *macsyma-ttyscan-operators*))
  948.       (declare (special *mread-prompt-internal*))
  949.       (SI:READ-APPLY ':MREAD #'MREAD-RAW (coerce READ-ARGS 'sys:vector)
  950.              '(:prompt mread-prompter)
  951.              '(:reprompt mread-prompter)))
  952.   #+cl (progn
  953.      (when *mread-prompt*
  954.            (and *parse-window* (setf (car *parse-window*) nil
  955.                      *parse-window* (cdr *parse-window*)))
  956.            (princ *mread-prompt*))
  957.      (#+lispm read-apply #-lispm apply 'mread-raw read-args)
  958.             )
  959.   #-(or NIL cl)
  960.   (READ-APPLY #'MREAD-RAW READ-ARGS))
  961.  
  962. (defun mread-prompter (stream char)
  963.   (declare (special *mread-prompt-internal*))
  964.   char ;  (declare (ignore char))
  965.   (fresh-line stream)
  966.   (princ *mread-prompt-internal* stream))
  967.  
  968. #+NIL
  969. (DEFUN MREAD-WITH-PROMPT (PROMPT)
  970.   (let ((*mread-prompt-internal* prompt)
  971.     (si:*ttyscan-dispatch-table *macsyma-ttyscan-operators*))
  972.     (declare (special *mread-prompt-internal*))
  973.     (SI:READ-APPLY ':MREAD #'MREAD-RAW (SYS:VECTOR)
  974.            '(:prompt mread-prompter)
  975.            '(:reprompt mread-prompter))))
  976.  
  977. ;; input can look like:
  978. ;;aa && bb && jim:3;
  979.  
  980.  
  981. (DEFUN MREAD-RAW (*PARSE-STREAM* &OPTIONAL *MREAD-EOF-OBJ*)
  982.   (LET ((SCAN-BUFFERED-TOKEN (LIST NIL))
  983.     *parse-tyi*
  984.     )
  985.     (IF (EQ SCAN-BUFFERED-TOKEN ;; a handly unique object for the EQ test.
  986.         (PEEK-ONE-TOKEN-G T SCAN-BUFFERED-TOKEN))
  987.     *MREAD-EOF-OBJ*
  988.     (DO ((LABELS ())
  989.          (INPUT (PARSE '$ANY 0.) (PARSE '$ANY 0.)))
  990.         (NIL)
  991.       (CASE (FIRST-C)
  992.         ((|$;| |$$|)
  993.           ;force a separate line info structure
  994.          (SETF *CURRENT-LINE-INFO* NIL)
  995.          (RETURN (LIST (MHEADER (POP-C))
  996.                (IF LABELS (CONS (MHEADER '|$[|) (NREVERSE LABELS)))
  997.                INPUT)))
  998.         ((|$&&|)
  999.          (POP-C)
  1000.          (IF (SYMBOLP INPUT)
  1001.          (PUSH INPUT LABELS)
  1002.          (MREAD-SYNERR "Invalid && tag. Tag must be a symbol")))
  1003.         (T
  1004.          (PARSE-BUG-ERR 'MREAD-RAW)))))))
  1005.  
  1006. ;;; (PARSE <mode> <rbp>)
  1007. ;;;
  1008. ;;;  This will parse an expression containing operators which have a higher
  1009. ;;;  left binding power than <rbp>, returning as soon as an operator of
  1010. ;;;  lesser or equal binding power is seen. The result will be in the given
  1011. ;;;  mode (which allows some control over the class of result expected). 
  1012. ;;;  Modes used are as follows:
  1013. ;;;    $ANY    = Match any type of expression
  1014. ;;;    $CLAUSE = Match only boolean expressions (or $ANY)
  1015. ;;;    $EXPR   = Match only mathematical expressions (or $ANY)
  1016. ;;;  If a mismatched mode occurs, a syntax error will be flagged. Eg,
  1017. ;;;  this is why "X^A*B" parses but "X^A AND B" does not. X^A is a $EXPR
  1018. ;;;  and not coercible to a $CLAUSE. See CONVERT.
  1019. ;;;
  1020. ;;;  <mode> is the required mode of the result.
  1021. ;;;  <rbp>  is the right binding power to use for the parse. When an
  1022. ;;;         LED-type operator is seen with a lower left binding power
  1023. ;;;         than <rbp>, this parse returns what it's seen so far rather
  1024. ;;;         than calling that operator.
  1025. ;;;
  1026.  
  1027. (DEFUN PARSE (MODE RBP) 
  1028.   (DO ((LEFT (NUD-CALL (POP-C))        ; Envoke the null left denotation
  1029.          (LED-CALL (POP-C) LEFT)))    ;  and keep calling LED ops as needed
  1030.       ((>= RBP (LBP (FIRST-C)))        ; Until next op lbp too low
  1031.        (CONVERT LEFT MODE))))        ;  in which case, return stuff seen
  1032.  
  1033. ;;; (PARSE-PREFIX <op>)
  1034. ;;;
  1035. ;;;  Parses prefix forms -- eg, -X or NOT FOO.
  1036. ;;;
  1037. ;;;  This should be the NUD property on an operator. It fires after <op>
  1038. ;;;  has been seen. It parses forward looking for one more expression
  1039. ;;;  according to its right binding power, returning
  1040. ;;;  ( <mode> . ((<op>) <arg1>) )
  1041.  
  1042. (DEFUN PARSE-PREFIX (OP)
  1043.   (LIST (POS OP)            ; Operator mode
  1044.     (MHEADER OP)            ; Standard Macsyma expression header
  1045.     (PARSE (RPOS OP) (RBP OP))))    ; Convert single argument for use
  1046.  
  1047. ;;; (PARSE-POSTFIX <op> <left>)
  1048. ;;;
  1049. ;;;  Parses postfix forms. eg, X!.
  1050. ;;;
  1051. ;;;  This should be the LED property of an operator. It fires after <left>
  1052. ;;;  has been accumulated and <op> has been seen and gobbled up. It returns
  1053. ;;;  ( <mode> . ((<op>) <arg1>) )
  1054.  
  1055. (DEFUN PARSE-POSTFIX (OP L)
  1056.   (LIST (POS OP)            ; Operator's mode
  1057.     (MHEADER OP)            ; Standard Macsyma expression header
  1058.     (CONVERT L (LPOS OP))))        ; Convert single argument for use
  1059.  
  1060. ;;; (PARSE-INFIX <op> <left>)
  1061. ;;;
  1062. ;;;  Parses infix (non-nary) forms. eg, 5 mod 3.
  1063. ;;;
  1064. ;;;  This should be the led property of an operator. It fires after <left>
  1065. ;;;  has been accumulated and <op> has been seen and gobbled up. It returns
  1066. ;;;  ( <mode> . ((<op>) <arg1> <arg2>) )
  1067.  
  1068. (DEFUN PARSE-INFIX (OP L)
  1069.   (LIST (POS OP)            ; Operator's mode
  1070.     (MHEADER OP)            ; Standard Macsyma expression header
  1071.     (CONVERT L (LPOS OP))        ; Convert arg1 for immediate use
  1072.     (PARSE (RPOS OP) (RBP OP))))    ; Look for an arg2 
  1073.  
  1074. ;;; (PARSE-NARY <op> <left>)
  1075. ;;;
  1076. ;;;  Parses nary forms. Eg, form1*form2*... or form1+form2+...
  1077. ;;;  This should be the LED property on an operator. It fires after <op>
  1078. ;;;  has been seen, accumulating and returning
  1079. ;;;  ( <mode> . ((<op>) <arg1> <arg2> ...) )
  1080. ;;;
  1081. ;;;  <op>   is the being parsed.
  1082. ;;;  <left> is the stuff that has been seen to the left of <op> which 
  1083. ;;;         rightly belongs to <op> on the basis of parse precedence rules.
  1084.  
  1085. (DEFUN PARSE-NARY (OP L)
  1086.   (LIST* (POS OP)                ; Operator's mode
  1087.      (MHEADER OP)                ; Normal Macsyma operator header
  1088.      (CONVERT L (LPOS OP))            ; Check type-match of arg1
  1089.      (PRSNARY OP (LPOS OP) (LBP OP))))  ; Search for other args
  1090.  
  1091. ;;; (PARSE-MATCHFIX <lop>)
  1092. ;;;
  1093. ;;;  Parses matchfix forms. eg, [form1,form2,...] or (form1,form2,...)
  1094. ;;;
  1095. ;;;  This should be the NUD property on an operator. It fires after <op>
  1096. ;;;  has been seen. It parses <lop><form1>,<form2>,...<rop> returning
  1097. ;;;  ( <mode> . ((<lop>) <form1> <form2> ...) ).
  1098.  
  1099. (DEFUN PARSE-MATCHFIX (OP)
  1100.   (LIST* (POS OP)                     ; Operator's mode
  1101.      (MHEADER OP)                     ; Normal Macsyma operator header
  1102.      (PRSMATCH (SAFE-GET OP 'MATCH) (LPOS OP))))  ; Search for matchfixed forms
  1103.  
  1104. ;;; (PARSE-NOFIX <op>)
  1105. ;;;
  1106. ;;;  Parses an operator of no args. eg, @+X where @ designates a function
  1107. ;;;  call (eg, @() is implicitly stated by the lone symbol @.)
  1108. ;;;
  1109. ;;;  This should be a NUD property on an operator which takes no args.
  1110. ;;;  It immediately returns ( <mode> . ((<op>)) ).
  1111. ;;;
  1112. ;;;  <op> is the name of the operator.
  1113. ;;;
  1114. ;;;  Note: This is not used by default and probably shouldn't be used by 
  1115. ;;;   someone who doesn't know what he's doing. Example lossage. If @ is 
  1116. ;;;   a nofix op, then @(3,4) parses, but parses as "@"()(3,4) would -- ie, 
  1117. ;;;   to ((MQAPPLY) (($@)) 3 4) which is perhaps not what the user will expect.
  1118.  
  1119. (DEFUN PARSE-NOFIX (OP) (LIST (POS OP) (MHEADER OP)))
  1120.  
  1121. ;;; (PRSNARY <op> <mode> <rbp>)
  1122. ;;;
  1123. ;;;  Parses an nary operator tail Eg, ...form2+form3+... or ...form2*form3*...
  1124. ;;;
  1125. ;;;  Expects to be entered after the leading form and the first call to an 
  1126. ;;;  nary operator has been seen and popped. Returns a list of parsed forms
  1127. ;;;  which belong to that operator. Eg, for X+Y+Z; this should be called 
  1128. ;;;  after the first + is popped. Returns (Y Z) and leaves the ; token
  1129. ;;;  in the parser scan buffer.
  1130. ;;;
  1131. ;;;  <op>   is the nary operator in question.
  1132. ;;;  <rbp>  is (LBP <op>) and is provided for efficiency. It is for use in
  1133. ;;;         recursive parses as a binding power to parse for.
  1134. ;;;  <mode> is the name of the mode that each form must be.
  1135.  
  1136. (DEFUN PRSNARY (OP MODE RBP) 
  1137.   (DO ((NL (LIST (PARSE MODE RBP))       ; Get at least one form
  1138.        (CONS (PARSE MODE RBP) NL)))       ;  and keep getting forms
  1139.       ((NOT (EQ OP (FIRST-C)))           ; until a parse pops on a new op
  1140.        (NREVERSE NL))               ;  at which time return forms
  1141.       (POP-C)))                   ; otherwise pop op
  1142.  
  1143. ;;; (PRSMATCH <match> <mode>)
  1144. ;;;
  1145. ;;; Parses a matchfix sequence. Eg, [form1,form2,...] or (form1,form2,...)
  1146. ;;; Expects to be entered after the leading token is the popped (ie, at the
  1147. ;;;  point where the parse of form1 will begin). Returns (form1 form2 ...).
  1148. ;;;
  1149. ;;; <match> is the token to look for as a matchfix character.
  1150. ;;; <mode>  is the name of the mode that each form must be.
  1151.  
  1152. (DEFUN PRSMATCH (MATCH MODE)              ; Parse for matchfix char
  1153.   (COND ((EQ MATCH (FIRST-C)) (POP-C) NIL)      ; If immediate match, ()
  1154.     (T                      ; Else, ...
  1155.      (DO ((NL (LIST (PARSE MODE 10.))      ;  Get first element
  1156.           (CONS (PARSE MODE 10.) NL)))      ;   and Keep adding elements
  1157.          ((EQ MATCH (FIRST-C))          ;  Until we hit the match.
  1158.           (POP-C)                  ;   Throw away match.
  1159.           (NREVERSE NL))              ;   Put result back in order
  1160.        (IF (EQ '|$,| (FIRST-C))          ;  If not end, look for ","
  1161.            (POP-C)                  ;   and pop it if it's there
  1162.            (MREAD-SYNERR "Missing ~A"      ;   or give an error message.
  1163.                  (MOPSTRIP MATCH)))))))
  1164.  
  1165. ;;; (CONVERT <exp> <mode>)
  1166. ;;;
  1167. ;;;  Parser coercion function.
  1168. ;;;
  1169. ;;;  <exp>  should have the form ( <expressionmode> . <expression> )
  1170. ;;;  <mode> is the target mode.
  1171. ;;;
  1172. ;;;  If <expressionmode> and <mode> are compatible, returns <expression>.
  1173.  
  1174. (DEFUN CONVERT (ITEM MODE) 
  1175.   (IF (OR (EQ MODE (CAR ITEM))        ; If modes match exactly
  1176.       (EQ '$ANY MODE)        ;    or target is $ANY
  1177.       (EQ '$ANY (CAR ITEM)))    ;    or input is $ANY
  1178.       (CDR ITEM)            ;  then return expression
  1179.       (MREAD-SYNERR "Found ~A expression where ~A expression expected" 
  1180.             (GET (CAR ITEM) 'ENGLISH)
  1181.             (GET MODE       'ENGLISH))))
  1182.  
  1183. (DEFPROP $ANY    "untyped"   ENGLISH)
  1184. (DEFPROP $CLAUSE "logical"   ENGLISH)
  1185. (DEFPROP $EXPR   "algebraic" ENGLISH)
  1186.  
  1187.  
  1188. ;;;; Parser Error Diagnostics
  1189.  
  1190.  ;; Call this for random user-generated parse errors
  1191.  
  1192. (DEFUN PARSE-ERR () (MREAD-SYNERR "Syntax error")) 
  1193.  
  1194.  ;; Call this for random internal parser lossage (eg, code that shouldn't
  1195.  ;;  be reachable.)
  1196.  
  1197. (DEFUN PARSE-BUG-ERR (OP)
  1198.   (MREAD-SYNERR
  1199.     "Parser bug in ~A. Please report this to the Macsyma maintainers,~
  1200.    ~%including the characters you just typed which caused the error. Thanks."
  1201.     (MOPSTRIP OP)))
  1202.  
  1203. ;;; Random shared error messages
  1204.  
  1205. (DEFUN DELIM-ERR (OP)
  1206.   (MREAD-SYNERR "Illegal use of delimiter ~A" (MOPSTRIP OP)))
  1207.  
  1208. (DEFUN ERB-ERR (OP L) L ;Ignored
  1209.   (MREAD-SYNERR "Too many ~A's" (MOPSTRIP OP)))
  1210.  
  1211. (DEFUN PREMTERM-ERR (OP)
  1212.   (MREAD-SYNERR "Premature termination of input at ~A."
  1213.         (MOPSTRIP OP)))
  1214.  
  1215.  
  1216. ;;;; Operator Specific Data
  1217.  
  1218. (DEF-NUD-EQUIV |$]| DELIM-ERR)
  1219. (DEF-LED-EQUIV |$]| ERB-ERR)
  1220. (DEF-LBP     |$]| 5.)
  1221.  
  1222. (DEF-NUD-EQUIV    |$[| PARSE-MATCHFIX)
  1223. (DEF-MATCH    |$[| |$]|)
  1224. (DEF-LBP    |$[| 200.)
  1225. ;No RBP
  1226. (DEF-MHEADER    |$[| (MLIST))
  1227. (DEF-POS    |$[| $ANY)
  1228. (DEF-LPOS    |$[| $ANY)
  1229. ;No RPOS
  1230.  
  1231. (DEF-LED (|$[| 200.) (OP LEFT)
  1232.   (SETQ LEFT (CONVERT LEFT '$ANY))
  1233.   (IF (NUMBERP LEFT) (PARSE-ERR))            ; number[...] invalid
  1234.   (LET ((header (if (atom left)
  1235.             (add-lineinfo (LIST (AMPERCHK LEFT) 'array))
  1236.           (add-lineinfo '(MQAPPLY ARRAY))))
  1237.           
  1238.     (RIGHT (PRSMATCH '|$]| '$ANY)))            ; get sublist in RIGHT
  1239.     (COND ((NULL RIGHT)                    ; 1 subscript minimum
  1240.        (MREAD-SYNERR "No subscripts given"))
  1241.       ((ATOM LEFT)                    ; atom[...]
  1242.        (SETQ RIGHT (CONS header
  1243.                  RIGHT))
  1244.        (CONS '$ANY (ALIASLOOKUP RIGHT)))
  1245.       (T                        ; exp[...]
  1246.        (CONS '$ANY (CONS header
  1247.                  (CONS LEFT RIGHT)))))))
  1248.  
  1249.  
  1250. (DEF-NUD-EQUIV |$)| DELIM-ERR)
  1251. (DEF-LED-EQUIV |$)| ERB-ERR)
  1252. (DEF-LBP       |$)| 5.)
  1253.  
  1254. (DEF-MHEADER   |$(| (MPROGN))
  1255.  
  1256.   ;; KMP: This function optimizes out (exp) into just exp. 
  1257.   ;;  This is useful for mathy expressions, but obnoxious for non-mathy
  1258.   ;;  expressions. I think DISPLA should be made smart about such things,
  1259.   ;;  but probably the (...) should be carried around in the internal 
  1260.   ;;  representation. This would make things like BUILDQ much easier to 
  1261.   ;;  work with.
  1262.   ;; GJC: CGOL has the same behavior, so users tend to write extensions
  1263.   ;;  to the parser rather than write Macros per se. The transformation
  1264.   ;;  "(EXP)" ==> "EXP" is done by the evaluator anyway, the problem
  1265.   ;;  comes inside quoted expressions. There are many other problems with
  1266.   ;;  the "QUOTE" concept however.
  1267.  
  1268. (DEF-NUD (|$(| 200.) (OP)
  1269.   (LET ((RIGHT)(hdr (MHEADER '|$(|)))        ; make mheader first for lineinfo
  1270.     (COND ((EQ '|$)| (FIRST-C)) (PARSE-ERR))          ; () is illegal
  1271.       ((OR (NULL (SETQ RIGHT (PRSMATCH '|$)| '$ANY))) ; No args to MPROGN??
  1272.            (CDR RIGHT))                  ;  More than one arg.
  1273.        (CONS '$ANY (CONS hdr RIGHT)))      ; Return an MPROGN
  1274.       (T (CONS '$ANY (CAR RIGHT))))))          ; Optimize out MPROGN
  1275.  
  1276. (DEF-LED (|$(| 200.) (OP LEFT)
  1277.   (SETQ LEFT (CONVERT LEFT '$ANY))                ;De-reference LEFT
  1278.   (IF (NUMBERP LEFT) (PARSE-ERR))            ;number(...) illegal
  1279.   (LET ((HDR (AND (ATOM LEFT)(MHEADER (AMPERCHK LEFT))))
  1280.     (R (PRSMATCH '|$)| '$ANY))                       ;Get arglist in R
  1281.     )
  1282.     (CONS '$ANY                        ;Result is type $ANY
  1283.       (COND ((ATOM LEFT)                ;If atom(...) =>
  1284.          (CONS hdr R))    ;(($atom) exp . args)
  1285.         (T                        ;Else exp(...) =>
  1286.          (CONS '(MQAPPLY) (CONS LEFT R)))))))    ;((MQAPPLY) op . args)
  1287.  
  1288. (DEF-MHEADER |$'| (MQUOTE))
  1289.  
  1290. (DEF-NUD (|$'|) (OP)
  1291.   (LET (RIGHT)
  1292.     (COND ((EQ '|$(| (FIRST-C))
  1293.        (LIST '$ANY (MHEADER '|$'|) (PARSE '$ANY 190.)))
  1294.       ((OR (ATOM (SETQ RIGHT (PARSE '$ANY 190.)))
  1295.            (MEMQ (CAAR RIGHT) '(MQUOTE MLIST MPROG MPROGN LAMBDA)))
  1296.        (LIST '$ANY (MHEADER '|$'|) RIGHT))
  1297.       ((EQ 'MQAPPLY (CAAR RIGHT))
  1298.        (COND ((EQ (CAAADR RIGHT) 'LAMBDA)
  1299.           (LIST '$ANY (MHEADER '|$'|) RIGHT))
  1300.          (T (RPLACA (CDR RIGHT)
  1301.                 (CONS (CONS ($NOUNIFY (CAAADR RIGHT))
  1302.                     (CDAADR RIGHT))
  1303.                   (CDADR RIGHT)))
  1304.             (CONS '$ANY RIGHT))))
  1305.       (T (CONS '$ANY (CONS (CONS ($NOUNIFY (CAAR RIGHT)) (CDAR RIGHT))
  1306.                    (CDR RIGHT)))))))
  1307.  
  1308. (DEF-NUD (|$''|) (OP)
  1309.   (LET (RIGHT)
  1310.     (CONS '$ANY
  1311.       (COND ((EQ '|$(| (FIRST-C))  (MEVAL (PARSE '$ANY 190.)))
  1312.         ((ATOM (SETQ RIGHT (PARSE '$ANY 190.))) (MEVAL1 RIGHT))
  1313.         ((EQ 'MQAPPLY (CAAR RIGHT))
  1314.          (RPLACA (CDR RIGHT)
  1315.              (CONS (CONS ($VERBIFY (CAAADR RIGHT)) (CDAADR RIGHT))
  1316.                    (CDADR RIGHT)))
  1317.          RIGHT)
  1318.         (T (CONS (CONS ($VERBIFY (CAAR RIGHT)) (CDAR RIGHT))
  1319.              (CDR RIGHT)))))))
  1320.  
  1321. (DEF-LED-EQUIV |$:| PARSE-INFIX)
  1322. (DEF-LBP       |$:| 180.)
  1323. (DEF-RBP       |$:|  20.)
  1324. (DEF-POS       |$:| $ANY)
  1325. (DEF-RPOS      |$:| $ANY)
  1326. (DEF-LPOS      |$:| $ANY)
  1327. (DEF-MHEADER   |$:| (MSETQ))
  1328.  
  1329. (DEF-LED-EQUIV |$::| PARSE-INFIX)
  1330. (DEF-LBP       |$::| 180.)
  1331. (DEF-RBP       |$::|  20.)
  1332. (DEF-POS       |$::| $ANY)
  1333. (DEF-RPOS      |$::| $ANY)
  1334. (DEF-LPOS      |$::| $ANY)
  1335. (DEF-MHEADER   |$::| (MSET))
  1336.  
  1337. (DEF-LED-EQUIV |$:=| PARSE-INFIX)
  1338. (DEF-LBP       |$:=| 180.)
  1339. (DEF-RBP       |$:=|  20.)
  1340. (DEF-POS       |$:=| $ANY)
  1341. (DEF-RPOS      |$:=| $ANY)
  1342. (DEF-LPOS      |$:=| $ANY)
  1343. (DEF-MHEADER   |$:=| (MDEFINE))
  1344.  
  1345. (DEF-LED-EQUIV |$::=| PARSE-INFIX)
  1346. (DEF-LBP       |$::=| 180.)
  1347. (DEF-RBP       |$::=|  20.)
  1348. (DEF-POS       |$::=| $ANY)
  1349. (DEF-RPOS      |$::=| $ANY)
  1350. (DEF-LPOS      |$::=| $ANY)
  1351. (DEF-MHEADER   |$::=| (MDEFMACRO))
  1352.  
  1353. (DEF-LED-EQUIV    |$!| PARSE-POSTFIX)
  1354. (DEF-LBP    |$!| 160.)
  1355. ;No RBP
  1356. (DEF-POS    |$!| $EXPR)
  1357. (DEF-LPOS    |$!| $EXPR)
  1358. ;No RPOS
  1359. (DEF-MHEADER    |$!| (MFACTORIAL))
  1360.  
  1361. (DEF-MHEADER |$!!| ($GENFACT))
  1362.  
  1363. (DEF-LED (|$!!| 160.) (OP LEFT)
  1364.   (LIST '$EXPR
  1365.     (MHEADER '$!!)
  1366.     (CONVERT LEFT '$EXPR)
  1367.     (LIST (MHEADER '#-cl $// #+cl $/ ) (CONVERT LEFT '$EXPR) 2)
  1368.     2))
  1369.  
  1370. (DEF-LBP     |$^| 140.) 
  1371. (DEF-RBP     |$^| 139.)
  1372. (DEF-POS     |$^| $EXPR)
  1373. (DEF-LPOS    |$^| $EXPR)
  1374. (DEF-RPOS    |$^| $EXPR)
  1375. (DEF-MHEADER |$^| (MEXPT))
  1376.  
  1377. (DEF-LED ((|$^| |$^^|)) (OP LEFT)
  1378.   (CONS '$EXPR 
  1379.     (ALIASLOOKUP (LIST (MHEADER OP)
  1380.                (CONVERT LEFT (LPOS OP))
  1381.                (PARSE (RPOS OP) (RBP OP))))))
  1382.  
  1383. (MAPC #'(LAMBDA (PROP) ; Make $** like $^
  1384.       (LET ((PROPVAL (GET '$^ PROP)))
  1385.         (IF PROPVAL (PUTPROP '$** PROPVAL PROP))))
  1386.       '(LBP RBP POS RPOS LPOS MHEADER))
  1387. (INHERIT-PROPL  '$** '$^ (LED-PROPL))
  1388.  
  1389. (DEF-LBP     |$^^| 140.)
  1390. (DEF-RBP     |$^^| 139.)
  1391. (DEF-POS     |$^^| $EXPR)
  1392. (DEF-LPOS    |$^^| $EXPR)
  1393. (DEF-RPOS    |$^^| $EXPR)
  1394. (DEF-MHEADER |$^^| (MNCEXPT))
  1395.  
  1396. ;; note y^^4.z gives an error because it scans the number 4 together with
  1397. ;; the trailing '.' as a decimal place.    I think the error is correct.
  1398. (DEF-LED-EQUIV    |$.| PARSE-INFIX)
  1399. (DEF-LBP    |$.| 130.)
  1400. (DEF-RBP    |$.| 129.)
  1401. (DEF-POS    |$.| $EXPR)
  1402. (DEF-LPOS    |$.| $EXPR)
  1403. (DEF-RPOS    |$.| $EXPR)
  1404. (DEF-MHEADER    |$.| (MNCTIMES))
  1405.  
  1406. (DEF-LED-EQUIV    |$*| PARSE-NARY)
  1407. (DEF-LBP    |$*| 120.)
  1408. ;RBP not needed
  1409. (DEF-POS    |$*| $EXPR)
  1410. ;RPOS not needed
  1411. (DEF-LPOS    |$*| $EXPR)
  1412. (DEF-MHEADER    |$*| (MTIMES))
  1413.  
  1414. (DEF-LED-EQUIV    #-cl |$//| #+cl $/  PARSE-INFIX)
  1415. (DEF-LBP    #-cl |$//| #+cl $/  120.)
  1416. (DEF-RBP    #-cl |$//| #+cl $/  120.)
  1417. (DEF-POS    #-cl |$//| #+cl $/  $EXPR)
  1418. (DEF-RPOS    #-cl |$//| #+cl $/  $EXPR)
  1419. (DEF-LPOS    #-cl |$//| #+cl $/  $EXPR)
  1420. (DEF-MHEADER    #-cl |$//| #+cl $/  (MQUOTIENT))
  1421.  
  1422. (DEF-NUD-EQUIV    |$+| PARSE-PREFIX)
  1423. (DEF-LBP    |$+| 100.)
  1424. (DEF-RBP    |$+| 100.)
  1425. (DEF-POS    |$+| $EXPR)
  1426. (DEF-RPOS    |$+| $EXPR)
  1427. ;LPOS not needed
  1428. (DEF-MHEADER    |$+| (MPLUS))
  1429.  
  1430. (DEF-LED ((|$+| |$-|) 100.) (OP LEFT)
  1431.   (SETQ LEFT (CONVERT LEFT '$EXPR))
  1432.   (DO ((NL (LIST (IF (EQ OP '$-)
  1433.              (LIST (MHEADER '$-) (PARSE '$EXPR 100.))
  1434.              (PARSE '$EXPR 100.))
  1435.          LEFT)
  1436.        (CONS (PARSE '$EXPR 100.) NL)))
  1437.       ((NOT (MEMQ (FIRST-C) '($+ $-)))
  1438.        (LIST* '$EXPR (MHEADER '$+) (NREVERSE NL)))
  1439.     (IF (EQ (FIRST-C) '$+) (POP-C))))
  1440.  
  1441. (DEF-NUD-EQUIV    |$-| PARSE-PREFIX)
  1442. (DEF-LBP    |$-| 100.)
  1443. (DEF-RBP    |$-| 134.)
  1444. (DEF-POS    |$-| $EXPR)
  1445. (DEF-RPOS    |$-| $EXPR)
  1446. ;LPOS not needed
  1447. (DEF-MHEADER    |$-| (MMINUS))
  1448.  
  1449. (DEF-LED-EQUIV    |$=| PARSE-INFIX)
  1450. (DEF-LBP    |$=| 80.)
  1451. (DEF-RBP    |$=| 80.)
  1452. (DEF-POS    |$=| $CLAUSE)
  1453. (DEF-RPOS    |$=| $EXPR)
  1454. (DEF-LPOS    |$=| $EXPR)
  1455. (DEF-MHEADER    |$=| (MEQUAL))
  1456.  
  1457. (DEF-LED-EQUIV    |$#| PARSE-INFIX)
  1458. (DEF-LBP    |$#| 80.)
  1459. (DEF-RBP    |$#| 80.)
  1460. (DEF-POS    |$#| $CLAUSE)
  1461. (DEF-RPOS    |$#| $EXPR)
  1462. (DEF-LPOS    |$#| $EXPR)
  1463. (DEF-MHEADER    |$#| (MNOTEQUAL))
  1464.  
  1465. (DEF-LED-EQUIV    |$>| PARSE-INFIX)
  1466. (DEF-LBP    |$>| 80.)
  1467. (DEF-RBP    |$>| 80.)
  1468. (DEF-POS    |$>| $CLAUSE)
  1469. (DEF-RPOS    |$>| $EXPR)
  1470. (DEF-LPOS    |$>| $EXPR)
  1471. (DEF-MHEADER    |$>| (MGREATERP))
  1472.  
  1473. (DEF-LED-EQUIV    |$>=| PARSE-INFIX)
  1474. (DEF-LBP    |$>=| 80.)
  1475. (DEF-RBP    |$>=| 80.)
  1476. (DEF-POS    |$>=| $CLAUSE)
  1477. (DEF-RPOS    |$>=| $EXPR)
  1478. (DEF-LPOS    |$>=| $EXPR)
  1479. (DEF-MHEADER    |$>=| (MGEQP))
  1480.  
  1481.  
  1482. (DEF-NUD (|$>| 80.) (OP) ; > is a single-char object
  1483.   '($ANY . |$>|))
  1484.  
  1485. (DEF-LED-EQUIV    |$<| PARSE-INFIX)
  1486. (DEF-LBP    |$<| 80.)
  1487. (DEF-RBP    |$<| 80.)
  1488. (DEF-POS    |$<| $CLAUSE)
  1489. (DEF-RPOS    |$<| $EXPR)
  1490. (DEF-LPOS    |$<| $EXPR)
  1491. (DEF-MHEADER    |$<| (MLESSP))
  1492.  
  1493. (DEF-LED-EQUIV    |$<=| PARSE-INFIX)
  1494. (DEF-LBP    |$<=| 80.)
  1495. (DEF-RBP    |$<=| 80.)
  1496. (DEF-POS    |$<=| $CLAUSE)
  1497. (DEF-RPOS    |$<=| $EXPR)
  1498. (DEF-LPOS    |$<=| $EXPR)
  1499. (DEF-MHEADER    |$<=| (MLEQP))
  1500.  
  1501. (DEF-NUD-EQUIV    |$NOT| PARSE-PREFIX)
  1502. ;LBP not needed
  1503. (DEF-RBP    |$NOT| 70.)
  1504. (DEF-POS    |$NOT| $CLAUSE)
  1505. (DEF-RPOS    |$NOT| $CLAUSE)
  1506. (DEF-LPOS    |$NOT| $CLAUSE)
  1507. (DEF-MHEADER    |$NOT| (MNOT))
  1508.  
  1509. (DEF-LED-EQUIV    |$AND| PARSE-NARY)
  1510. (DEF-LBP    |$AND| 65.)
  1511. ;RBP not needed
  1512. (DEF-POS    |$AND| $CLAUSE)
  1513. ;RPOS not needed
  1514. (DEF-LPOS    |$AND| $CLAUSE)
  1515. (DEF-MHEADER    |$AND| (MAND))
  1516.  
  1517. (DEF-LED-EQUIV    |$OR| PARSE-NARY)
  1518. (DEF-LBP    |$OR| 60.)
  1519. ;RBP not needed
  1520. (DEF-POS    |$OR| $CLAUSE)
  1521. ;RPOS not needed
  1522. (DEF-LPOS    |$OR| $CLAUSE)
  1523. (DEF-MHEADER    |$OR| (MOR))
  1524.  
  1525. (DEF-LED-EQUIV    |$,| PARSE-NARY)
  1526. (DEF-LBP    |$,| 10.)
  1527. ;RBP not needed
  1528. (DEF-POS    |$,| $ANY)
  1529. ;RPOS not needed
  1530. (DEF-LPOS    |$,| $ANY)
  1531. (DEF-MHEADER    |$,| ($EV))
  1532.  
  1533. (DEF-NUD-EQUIV |$THEN| DELIM-ERR)
  1534. (DEF-LBP |$THEN| 5.)
  1535. (DEF-RBP |$THEN| 25.)
  1536.  
  1537. (DEF-NUD-EQUIV |$ELSE| DELIM-ERR)
  1538. (DEF-LBP |$ELSE| 5.)
  1539. (DEF-RBP |$ELSE| 25.)
  1540.  
  1541. (DEF-NUD-EQUIV |$ELSEIF| DELIM-ERR)
  1542. (DEF-LBP  |$ELSEIF| 5.)
  1543. (DEF-RBP  |$ELSEIF| 45.)
  1544. (DEF-POS  |$ELSEIF| $ANY)
  1545. (DEF-RPOS |$ELSEIF| $CLAUSE)
  1546.  
  1547. ;No LBP - Default as high as possible
  1548. (DEF-RBP     $IF 45.)
  1549. (DEF-POS     $IF $ANY)
  1550. (DEF-RPOS    $IF $CLAUSE)
  1551. ;No LPOS
  1552. (DEF-MHEADER $IF (MCOND))
  1553.  
  1554. (DEF-NUD (|$IF|) (OP)
  1555.   (LIST* (POS OP)
  1556.      (MHEADER OP)
  1557.      (PARSE-CONDITION OP)))
  1558.  
  1559. (DEFUN PARSE-CONDITION (OP)
  1560.   (LIST* (PARSE (RPOS OP) (RBP OP))
  1561.      (IF (EQ (FIRST-C) '$THEN)
  1562.          (PARSE '$ANY (RBP (POP-C)))
  1563.          (MREAD-SYNERR "Missing THEN"))
  1564.      (CASE (FIRST-C)
  1565.        (($ELSE)   (LIST T (PARSE '$ANY (RBP (POP-C)))))
  1566.        (($ELSEIF) (PARSE-CONDITION (POP-C)))
  1567.        (T ; Note: $FALSE instead of () makes DISPLA suppress display!
  1568.         (LIST T '$FALSE)))))
  1569.  
  1570. (DEF-MHEADER $DO (MDO))
  1571.  
  1572. (DEFUN PARSE-$DO (LEX &aux (left (make-mdo)))
  1573.   (setf (car LEFT) (mheader 'mdo))
  1574.   (DO ((OP LEX (POP-C))  (ACTIVE-BITMASK 0))
  1575.       (NIL)
  1576.     (IF (EQ OP '|$:|) (SETQ OP '$FROM))
  1577.     (SETQ ACTIVE-BITMASK (COLLISION-CHECK '$DO ACTIVE-BITMASK OP))
  1578.     (LET ((DATA (PARSE (RPOS OP) (RBP OP))))
  1579.       (CASE OP
  1580.     ($DO        (SETF (MDO-BODY LEFT) DATA) (RETURN (CONS '$ANY LEFT)))
  1581.     ($FOR        (SETF (MDO-FOR  LEFT) DATA))
  1582.     ($FROM        (SETF (MDO-FROM LEFT) DATA))
  1583.     ($IN        (SETF (MDO-OP   LEFT) 'MDOIN)
  1584.             (SETF (MDO-FROM LEFT) DATA))
  1585.     ($STEP        (SETF (MDO-STEP LEFT) DATA))
  1586.     ($NEXT        (SETF (MDO-NEXT LEFT) DATA))
  1587.     ($THRU        (SETF (MDO-THRU LEFT) DATA))
  1588.     (($UNLESS $WHILE)
  1589.             (IF (EQ OP '$WHILE)
  1590.                 (SETQ DATA (LIST (MHEADER '$NOT) DATA)))
  1591.             (SETF (MDO-UNLESS LEFT)
  1592.                (IF (NULL (MDO-UNLESS LEFT))
  1593.                    DATA
  1594.                    (LIST (MHEADER '$OR) DATA (MDO-UNLESS LEFT)))))
  1595.     (T (PARSE-BUG-ERR '$DO))))))
  1596.  
  1597. (DEF-LBP $FOR    25.)
  1598. (DEF-LBP $FROM   25.)
  1599. (DEF-LBP $STEP   25.)
  1600. (DEF-LBP $NEXT   25.)
  1601. (DEF-LBP $THRU   25.)
  1602. (DEF-LBP $UNLESS 25.)
  1603. (DEF-LBP $WHILE  25.)
  1604. (DEF-LBP $DO     25.)
  1605.  
  1606. (DEF-NUD-EQUIV $FOR    PARSE-$DO)
  1607. (DEF-NUD-EQUIV $FROM   PARSE-$DO)
  1608. (DEF-NUD-EQUIV $STEP   PARSE-$DO)
  1609. (DEF-NUD-EQUIV $NEXT   PARSE-$DO)
  1610. (DEF-NUD-EQUIV $THRU   PARSE-$DO)
  1611. (DEF-NUD-EQUIV $UNLESS PARSE-$DO)
  1612. (DEF-NUD-EQUIV $WHILE  PARSE-$DO)
  1613. (DEF-NUD-EQUIV $DO     PARSE-$DO)
  1614.  
  1615. (DEF-RBP $DO      25.)
  1616. (DEF-RBP $FOR    200.)
  1617. (DEF-RBP $FROM    95.)
  1618. (DEF-RBP $IN      95.)
  1619. (DEF-RBP $STEP    95.)
  1620. (DEF-RBP $NEXT    45.)
  1621. (DEF-RBP $THRU    95.)
  1622. (DEF-RBP $UNLESS  45.)
  1623. (DEF-RBP $WHILE      45.)
  1624.  
  1625. (DEF-RPOS $DO     $ANY)
  1626. (DEF-RPOS $FOR    $ANY)
  1627. (DEF-RPOS $FROM   $ANY)
  1628. (DEF-RPOS $STEP   $EXPR)
  1629. (DEF-RPOS $NEXT   $ANY)
  1630. (DEF-RPOS $THRU   $EXPR)
  1631. (DEF-RPOS $UNLESS $CLAUSE)
  1632. (DEF-RPOS $WHILE  $CLAUSE)
  1633.  
  1634.  
  1635. (DEF-COLLISIONS $DO
  1636.   ($DO       . ())
  1637.   ($FOR    . ($FOR))
  1638.   ($FROM   . ($IN $FROM))
  1639.   ($IN     . ($IN $FROM $STEP $NEXT))
  1640.   ($STEP   . ($IN       $STEP $NEXT))
  1641.   ($NEXT   . ($IN    $STEP $NEXT))
  1642.   ($THRU   . ($IN $THRU)) ;$IN didn't used to get checked for
  1643.   ($UNLESS . ())
  1644.   ($WHILE  . ()))
  1645.  
  1646. #+ti  ;;because of a bug the preceding doesn't give this..
  1647. (defprop $do (($WHILE . 256) ($UNLESS . 128)
  1648.                 ($THRU . 64)
  1649.                 ($NEXT . 32)
  1650.                 ($STEP . 16)
  1651.                 ($IN . 8)
  1652.                 ($FROM . 4)
  1653.                 ($FOR . 2)
  1654.                 ($DO . 1)) keys)
  1655.  
  1656.  
  1657. (DEF-MHEADER   |$$| (NODISPLAYINPUT))
  1658. (DEF-NUD-EQUIV |$$| PREMTERM-ERR)
  1659. (DEF-LBP       |$$| -1)
  1660. ;No RBP, POS, RPOS, RBP, or MHEADER
  1661.  
  1662. (DEF-MHEADER   |$;| (DISPLAYINPUT))
  1663. (DEF-NUD-EQUIV |$;| PREMTERM-ERR)
  1664. (DEF-LBP       |$;| -1)
  1665. ;No RBP, POS, RPOS, RBP, or MHEADER
  1666.  
  1667. (DEF-NUD-EQUIV  |$&&| DELIM-ERR)
  1668. (DEF-LBP    |$&&| -1)
  1669.  
  1670. (defun MOPSTRIP (x)
  1671.   ;; kludge interface function to allow the use of lisp PRINC in places.
  1672.   (COND ((NULL X) 'FALSE)
  1673.     ((OR (EQ X T) (EQ X 'T)) 'TRUE)
  1674.     ((NUMBERP X) X)
  1675.     ((SYMBOLP X)
  1676.      (OR (GET X 'REVERSEALIAS)
  1677.          (IF (IMEMBER (FIRSTCHARN X) '(#\$ #\% #\&))
  1678.          (IMPLODE (CDR (EXPLODEN X)))
  1679.          X)))
  1680.     (T (MAKNAM (MSTRING X)))))
  1681.     
  1682.  
  1683. (DEFINE-INITIAL-SYMBOLS
  1684.   ;; * Note: /. is looked for explicitly rather than
  1685.   ;;     existing in this chart. The reason is that
  1686.   ;;     it serves a dual role (as a decimal point) and
  1687.   ;;     must be special-cased.
  1688.   ;;
  1689.   ;;     Same for // because of the /* ... */ handling
  1690.   ;;     by the tokenizer
  1691.   ;; Single character
  1692.   |+| |-| |*| |^| |<| |=| |>| |(| |)| |[| |]| |,|
  1693.   |:| |!| |#| |'| |;| |$| |&|            
  1694.   ;;Two character
  1695.   |**| |^^| |:=| |::| |!!| |<=| |>=| |''| |&&|             
  1696.   ;; Three character
  1697.   |::=|
  1698.   )
  1699.  
  1700. ;;; User extensibility:
  1701. (defmacro upcase (operator)
  1702.  `(setq operator (intern (string-upcase (string ,operator)))))
  1703.  
  1704. (DEFMFUN $PREFIX (OPERATOR &OPTIONAL (RBP  180.)
  1705.                          (RPOS '$ANY)
  1706.                      (POS  '$ANY))
  1707.      (upcase operator)
  1708.   (DEF-OPERATOR OPERATOR POS ()  ()     RBP RPOS () T
  1709.     '(NUD . PARSE-PREFIX) 'MSIZE-PREFIX 'DIMENSION-PREFIX ()   ))
  1710.  
  1711. (DEFMFUN $POSTFIX (OPERATOR &OPTIONAL (LBP  180.)
  1712.                          (LPOS '$ANY)
  1713.                      (POS  '$ANY))
  1714.           (upcase operator)
  1715.   (DEF-OPERATOR OPERATOR POS LBP LPOS   ()  ()   T  ()
  1716.     '(LED . PARSE-POSTFIX) 'MSIZE-POSTFIX 'DIMENSION-POSTFIX  ()   ))
  1717.  
  1718. (DEFMFUN $INFIX  (OPERATOR &OPTIONAL (LBP  180.)
  1719.                          (RBP  180.)
  1720.                      (LPOS '$ANY)
  1721.                      (RPOS '$ANY)
  1722.                      (POS  '$ANY))
  1723.           (upcase operator)
  1724.   (DEF-OPERATOR OPERATOR POS LBP LPOS   RBP RPOS T T
  1725.     '(LED . PARSE-INFIX) 'MSIZE-INFIX 'DIMENSION-INFIX () ))
  1726.  
  1727. (DEFMFUN $NARY   (OPERATOR &OPTIONAL (BP     180.)
  1728.                          (ARGPOS '$ANY)
  1729.                      (POS    '$ANY))
  1730.           (upcase operator)
  1731.   (DEF-OPERATOR OPERATOR POS BP  ARGPOS BP  ()   T T
  1732.     '(LED . PARSE-NARY) 'MSIZE-NARY 'DIMENSION-NARY () ))
  1733.  
  1734. (DEFMFUN $MATCHFIX (OPERATOR
  1735.             MATCH  &OPTIONAL (ARGPOS '$ANY)
  1736.                      (POS    '$ANY))
  1737.   ;shouldn't MATCH be optional?
  1738.           (upcase operator)
  1739.   (DEF-OPERATOR OPERATOR POS ()  ARGPOS ()  ()  () () 
  1740.     '(NUD . PARSE-MATCHFIX) 'MSIZE-MATCHFIX 'DIMENSION-MATCH MATCH))
  1741.  
  1742. (DEFMFUN $NOFIX  (OPERATOR &OPTIONAL (POS '$ANY))
  1743.           (upcase operator)
  1744.   (DEF-OPERATOR OPERATOR POS ()  ()     ()  () () ()
  1745.     '(NUD . PARSE-NOFIX) 'MSIZE-NOFIX 'DIMENSION-NOFIX ()   ))
  1746.  
  1747.  
  1748. ;;; (DEF-OPERATOR op pos lbp lpos rbp rpos sp1 sp2 
  1749. ;;;    parse-data grind-fn dim-fn match)
  1750. ;;; OP        is the operator name.
  1751. ;;; POS       is its ``part of speech.''
  1752. ;;; LBP       is its ``left binding power.''
  1753. ;;; LPOS      is the part of speech of the arguments to its left, or of all.
  1754. ;;;            arguments for NARY and MATCHFIX.
  1755. ;;; RBP       is its ``right binding power.''
  1756. ;;; RPOS      is the part of speech of the argument to its right.
  1757. ;;; SP1       says if the DISSYM property needs a space on the right.
  1758. ;;; SP2       says if the DISSYM property needs a space on the left.
  1759. ;;; PARSE-DATA is (prop . fn) -- parser prop name dotted with function name
  1760. ;;; GRIND-FN  is the grinder function for the operator.
  1761. ;;; DIM-FN    is the dimension function for the operator.
  1762. ;;; PARSEPROP is the property name to use for parsing. One of LED or NUD.
  1763. ;;; MATCH     if non-(), ignores SP1 and SP2. Should be the match symbol.
  1764. ;;;            sets OP up as matchfix with MATCH.
  1765. ;;;
  1766. ;;; For more complete descriptions of these naming conventions, see
  1767. ;;; the comments in GRAM package, which describe them in reasonable detail.
  1768.  
  1769. (DEFUN DEF-OPERATOR (OP POS LBP LPOS RBP RPOS SP1 SP2
  1770.             PARSE-DATA GRIND-FN DIM-FN MATCH)
  1771.   (LET ((X))
  1772.     (IF (OR (AND RBP (NOT (INTEGERP (SETQ X RBP))))
  1773.         (AND LBP (NOT (INTEGERP (SETQ X LBP)))))
  1774.     (MERROR "Binding powers must be integers.~%~M is not an integer." X))
  1775.     (IF (MSTRINGP OP) (SETQ OP (DEFINE-SYMBOL OP)))
  1776.     (OP-SETUP OP)
  1777.     (LET ((NOUN   ($NOUNIFY OP))
  1778.       (DISSYM (CDR (EXPLODEN OP))))
  1779.       (cond
  1780.        ((NOT MATCH)
  1781.     (SETQ DISSYM (APPEND (IF SP1 '(#\Space)) DISSYM (IF SP2 '(#\Space)))))
  1782.        (t (IF (MSTRINGP MATCH) (SETQ MATCH (DEFINE-SYMBOL MATCH)))
  1783.       (OP-SETUP MATCH)
  1784.       (PUTPROP OP    MATCH 'MATCH)
  1785.       (PUTPROP MATCH 5.    'LBP)
  1786.       (SETQ DISSYM (CONS DISSYM (CDR (EXPLODEN MATCH))))))
  1787.       (PUTPROP OP POS 'POS)
  1788.       (PUTPROP OP (CDR PARSE-DATA) (CAR PARSE-DATA))
  1789.       (PUTPROP OP   GRIND-FN  'GRIND)
  1790.       (PUTPROP OP   DIM-FN    'DIMENSION)
  1791.       (PUTPROP NOUN DIM-FN    'DIMENSION)
  1792.       (PUTPROP OP   DISSYM 'DISSYM)
  1793.       (PUTPROP NOUN DISSYM 'DISSYM)
  1794.       (WHEN RBP
  1795.     (PUTPROP OP   RBP  'RBP)
  1796.     (PUTPROP NOUN RBP  'RBP))
  1797.       (WHEN LBP
  1798.     (PUTPROP OP   LBP  'LBP)
  1799.     (PUTPROP NOUN LBP  'LBP))
  1800.       (WHEN LPOS (PUTPROP OP   LPOS 'LPOS))
  1801.       (WHEN RPOS (PUTPROP OP   RPOS 'RPOS))
  1802.       (GETOPR OP))))
  1803.  
  1804. (DEFUN OP-SETUP (OP)
  1805.   (declare (special mopl))
  1806.   (LET ((DUMMY (OR (GET OP 'OP)
  1807.            (IMPLODE (CONS '& (STRING* OP))))))
  1808.     (PUTPROP OP    DUMMY 'OP )
  1809.     (PUTPROP DUMMY OP    'OPR)
  1810.     (IF (AND (OPERATORP1 OP) (NOT (MEMQ DUMMY (CDR $PROPS))))
  1811.     (PUSH DUMMY MOPL))
  1812.     (ADD2LNC DUMMY $PROPS)))
  1813.  
  1814. (DEFUN KILL-OPERATOR (OP)
  1815.   (UNDEFINE-SYMBOL (STRIPDOLLAR OP))
  1816.   (LET ((OPR (GET OP 'OP)) (NOUN-FORM ($NOUNIFY OP)))
  1817.     (REMPROP OPR 'OPR)
  1818.     (REMPROPCHK OPR)
  1819.     (MAPC #'(LAMBDA (X) (REMPROP OP X))
  1820.        '(NUD-EXPR NUD-SUBR            ; NUD info
  1821.              LED LED-EXPR LED-SUBR        ; LED info
  1822.              LBP RBP            ; Binding power info
  1823.              LPOS RPOS POS        ; Part-Of-Speech info
  1824.              GRIND DIMENSION DISSYM    ; Display info
  1825.              OP
  1826.              ))            ; Operator info
  1827.     (MAPC #'(LAMBDA (X) (REMPROP NOUN-FORM X))
  1828.        '(DIMENSION DISSYM LBP RBP))))
  1829.  
  1830. (defun find-stream (stream)
  1831.    (dolist (v *stream-alist*)
  1832.     (cond ((eq stream (instream-stream v))
  1833.            (return v))))
  1834.   )
  1835.  
  1836.  
  1837. (defun add-lineinfo (lis)
  1838.   (if (or (atom lis) (and (eq *parse-window* *standard-input*)
  1839.               (not (find-stream *parse-stream*))))
  1840.               lis
  1841.     (let* ((st (get-instream *parse-stream*))
  1842.         (n (instream-line st))
  1843.        (nam (instream-name st))
  1844.        )
  1845.       (or nam (return-from add-lineinfo lis))
  1846.       (setq *current-line-info*
  1847.         (cond ((eq (cadr *current-line-info*) nam)
  1848.            (cond ((eql (car *current-line-info*) n)
  1849.               *current-line-info*)
  1850.              (t  (cons n (cdr *current-line-info*)))))
  1851.           (t (list n nam  'src))))
  1852.       (cond ((null (cdr lis))
  1853.          (list (car lis) *current-line-info*))
  1854.         (t (append lis (list *current-line-info*)))))))
  1855.  
  1856.  
  1857. ;; the functions get-instream etc.. are all defined in
  1858. ;; gcl lsp/debug.lsp
  1859. ;; they are all generic common lisp and could be used by
  1860. ;; any Common lisp implementation.
  1861.  
  1862.  
  1863. #-gcl
  1864. (eval-when (compile eval load)
  1865.  
  1866. (defvar *stream-alist* nil)
  1867.  
  1868. (defun instream-name (instr)
  1869.   (or (instream-stream-name instr)
  1870.       (stream-name (instream-stream instr))))
  1871.  
  1872. (defun stream-name (str) (namestring (pathname str)))
  1873.  
  1874. (defstruct instream stream (line 0 :type fixnum) stream-name)
  1875.  
  1876. ;; (closedp stream) checks if a stream is closed.. how to do this in common
  1877. ;; lisp!!
  1878.  
  1879. (defun cleanup ()
  1880.   #+never-clean-up-dont-know-how-to-close
  1881.   (dolist (v *stream-alist*)
  1882.     (if (closedp (instream-stream v))
  1883.     (setq *stream-alist* (delete v *stream-alist*)))))
  1884.  
  1885. (defun get-instream (str)
  1886.   (or (dolist (v *stream-alist*)
  1887.     (cond ((eq str (instream-stream v))
  1888.            (return v))))
  1889.       (let (name errset)
  1890.     (errset (setq name (namestring str)))
  1891.       (car (setq *stream-alist*
  1892.          (cons  (make-instream :stream str :stream-name name) *stream-alist*))))))
  1893.  
  1894.  
  1895.  
  1896. (defun newline (str ch) ch
  1897.   (let ((in (get-instream str)))
  1898.     (setf (instream-line in) (the fixnum (+ 1 (instream-line in)))))
  1899.   ;; if the next line begins with '(', then record all cons's eg arglist )
  1900.   ;(setq *at-newline*  (if (eql (peek-char nil str nil) #\() :all t))
  1901.   (values))
  1902.  
  1903. )
  1904. ; end #-gcl
  1905.